mirror of
https://github.com/overte-org/overte.git
synced 2025-07-04 15:49:21 +02:00
Merge branch 'workload' of https://github.com/highfidelity/hifi into workload
This commit is contained in:
commit
be3fdbeaeb
85 changed files with 2743 additions and 341 deletions
|
@ -21,12 +21,7 @@
|
||||||
#include "AssetUtils.h"
|
#include "AssetUtils.h"
|
||||||
#include "ReceivedMessage.h"
|
#include "ReceivedMessage.h"
|
||||||
|
|
||||||
namespace std {
|
#include "RegisteredMetaTypes.h"
|
||||||
template <>
|
|
||||||
struct hash<QString> {
|
|
||||||
size_t operator()(const QString& v) const { return qHash(v); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AssetMeta {
|
struct AssetMeta {
|
||||||
int bakeVersion { 0 };
|
int bakeVersion { 0 };
|
||||||
|
|
|
@ -22,6 +22,8 @@ setup_memory_debugger()
|
||||||
symlink_or_copy_directory_beside_target(${_SHOULD_SYMLINK_RESOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/resources" "resources")
|
symlink_or_copy_directory_beside_target(${_SHOULD_SYMLINK_RESOURCES} "${CMAKE_CURRENT_SOURCE_DIR}/resources" "resources")
|
||||||
|
|
||||||
# link the shared hifi libraries
|
# link the shared hifi libraries
|
||||||
|
include_hifi_library_headers(gpu)
|
||||||
|
include_hifi_library_headers(graphics)
|
||||||
link_hifi_libraries(embedded-webserver networking shared avatars)
|
link_hifi_libraries(embedded-webserver networking shared avatars)
|
||||||
|
|
||||||
# find OpenSSL
|
# find OpenSSL
|
||||||
|
|
|
@ -1196,8 +1196,8 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainServerSettingsManager::restoreSettingsFromObject(QJsonObject settingsToRestore, SettingsType settingsType) {
|
bool DomainServerSettingsManager::restoreSettingsFromObject(QJsonObject settingsToRestore, SettingsType settingsType) {
|
||||||
QJsonArray& filteredDescriptionArray = settingsType == DomainSettings
|
QJsonArray* filteredDescriptionArray = settingsType == DomainSettings
|
||||||
? _domainSettingsDescription : _contentSettingsDescription;
|
? &_domainSettingsDescription : &_contentSettingsDescription;
|
||||||
|
|
||||||
// grab a copy of the current config before restore, so that we can back out if something bad happens during
|
// grab a copy of the current config before restore, so that we can back out if something bad happens during
|
||||||
QVariantMap preRestoreConfig = _configMap.getConfig();
|
QVariantMap preRestoreConfig = _configMap.getConfig();
|
||||||
|
@ -1206,7 +1206,7 @@ bool DomainServerSettingsManager::restoreSettingsFromObject(QJsonObject settings
|
||||||
|
|
||||||
// enumerate through the settings in the description
|
// enumerate through the settings in the description
|
||||||
// if we have one in the restore then use it, otherwise clear it from current settings
|
// if we have one in the restore then use it, otherwise clear it from current settings
|
||||||
foreach(const QJsonValue& descriptionGroupValue, filteredDescriptionArray) {
|
foreach(const QJsonValue& descriptionGroupValue, *filteredDescriptionArray) {
|
||||||
QJsonObject descriptionGroupObject = descriptionGroupValue.toObject();
|
QJsonObject descriptionGroupObject = descriptionGroupValue.toObject();
|
||||||
QString groupKey = descriptionGroupObject[DESCRIPTION_NAME_KEY].toString();
|
QString groupKey = descriptionGroupObject[DESCRIPTION_NAME_KEY].toString();
|
||||||
QJsonArray descriptionGroupSettings = descriptionGroupObject[DESCRIPTION_SETTINGS_KEY].toArray();
|
QJsonArray descriptionGroupSettings = descriptionGroupObject[DESCRIPTION_SETTINGS_KEY].toArray();
|
||||||
|
@ -1328,15 +1328,15 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt
|
||||||
const QString AFFECTED_TYPES_JSON_KEY = "assignment-types";
|
const QString AFFECTED_TYPES_JSON_KEY = "assignment-types";
|
||||||
|
|
||||||
// only enumerate the requested settings type (domain setting or content setting)
|
// only enumerate the requested settings type (domain setting or content setting)
|
||||||
QJsonArray& filteredDescriptionArray = _descriptionArray;
|
QJsonArray* filteredDescriptionArray = &_descriptionArray;
|
||||||
if (includeDomainSettings && !includeContentSettings) {
|
if (includeDomainSettings && !includeContentSettings) {
|
||||||
filteredDescriptionArray = _domainSettingsDescription;
|
filteredDescriptionArray = &_domainSettingsDescription;
|
||||||
} else if (includeContentSettings && !includeDomainSettings) {
|
} else if (includeContentSettings && !includeDomainSettings) {
|
||||||
filteredDescriptionArray = _contentSettingsDescription;
|
filteredDescriptionArray = &_contentSettingsDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
// enumerate the groups in the potentially filtered object to find which settings to pass
|
// enumerate the groups in the potentially filtered object to find which settings to pass
|
||||||
foreach(const QJsonValue& groupValue, filteredDescriptionArray) {
|
foreach(const QJsonValue& groupValue, *filteredDescriptionArray) {
|
||||||
QJsonObject groupObject = groupValue.toObject();
|
QJsonObject groupObject = groupValue.toObject();
|
||||||
QString groupKey = groupObject[DESCRIPTION_NAME_KEY].toString();
|
QString groupKey = groupObject[DESCRIPTION_NAME_KEY].toString();
|
||||||
QJsonArray groupSettingsArray = groupObject[DESCRIPTION_SETTINGS_KEY].toArray();
|
QJsonArray groupSettingsArray = groupObject[DESCRIPTION_SETTINGS_KEY].toArray();
|
||||||
|
|
|
@ -342,7 +342,7 @@
|
||||||
<p>In High Fidelity, your private keys are used to securely access the contents of your Wallet and Purchases.</p>
|
<p>In High Fidelity, your private keys are used to securely access the contents of your Wallet and Purchases.</p>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<h3>Where are my private keys stored?"</h3>
|
<h3>Where are my private keys stored?</h3>
|
||||||
<p>By default, your private keys are only stored on your hard drive in High Fidelity Interface's <code>AppData</code> directory.</p>
|
<p>By default, your private keys are only stored on your hard drive in High Fidelity Interface's <code>AppData</code> directory.</p>
|
||||||
<p>Here is the file path of your hifikey - you can browse to it using your file explorer.</p>
|
<p>Here is the file path of your hifikey - you can browse to it using your file explorer.</p>
|
||||||
<div class="alert"> <code>HIFIKEY_PATH_REPLACEME</code> </div>
|
<div class="alert"> <code>HIFIKEY_PATH_REPLACEME</code> </div>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<path d="M348.5,162.5c1.7,0,3,1.4,3,3v181.4c0,1.7-1.3,3-3,3H167.2c-1.6,0-3-1.3-3-3V165.5c0-1.6,1.4-3,3-3H348.5 M348.5,145.5
|
||||||
|
H167.2c-11,0-20,9-20,20v181.4c0,11,9,20,20,20h181.4c11,0,20-9,20-20V165.5C368.5,154.5,359.6,145.5,348.5,145.5L348.5,145.5z"/>
|
||||||
|
<rect x="161.6" y="253.6" width="96.3" height="96.3"/>
|
||||||
|
<rect x="256.1" y="159.8" width="95.4" height="95.4"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 717 B |
|
@ -144,6 +144,17 @@ TabView {
|
||||||
editTabView.currentIndex = 4
|
editTabView.currentIndex = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NewEntityButton {
|
||||||
|
icon: "icons/create-icons/126-material-01.svg"
|
||||||
|
text: "MATERIAL"
|
||||||
|
onClicked: {
|
||||||
|
editRoot.sendToScript({
|
||||||
|
method: "newEntityButtonClicked", params: { buttonName: "newMaterialButton" }
|
||||||
|
});
|
||||||
|
editTabView.currentIndex = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HifiControls.Button {
|
HifiControls.Button {
|
||||||
|
|
174
interface/resources/qml/hifi/tablet/NewMaterialDialog.qml
Normal file
174
interface/resources/qml/hifi/tablet/NewMaterialDialog.qml
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
//
|
||||||
|
// NewMaterialDialog.qml
|
||||||
|
// qml/hifi
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 1/17/18
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||||
|
|
||||||
|
import "../../styles-uit"
|
||||||
|
import "../../controls-uit"
|
||||||
|
import "../dialogs"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: newMaterialDialog
|
||||||
|
// width: parent.width
|
||||||
|
// height: parent.height
|
||||||
|
HifiConstants { id: hifi }
|
||||||
|
color: hifi.colors.baseGray;
|
||||||
|
signal sendToScript(var message);
|
||||||
|
property bool keyboardEnabled: false
|
||||||
|
property bool punctuationMode: false
|
||||||
|
property bool keyboardRasied: false
|
||||||
|
|
||||||
|
function errorMessageBox(message) {
|
||||||
|
return desktop.messageBox({
|
||||||
|
icon: hifi.icons.warning,
|
||||||
|
defaultButton: OriginalDialogs.StandardButton.Ok,
|
||||||
|
title: "Error",
|
||||||
|
text: message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: column1
|
||||||
|
anchors.rightMargin: 10
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
anchors.bottomMargin: 10
|
||||||
|
anchors.topMargin: 10
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: keyboard.top
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: text1
|
||||||
|
text: qsTr("Material URL")
|
||||||
|
color: "#ffffff"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
TextInput {
|
||||||
|
id: materialURL
|
||||||
|
height: 20
|
||||||
|
text: qsTr("")
|
||||||
|
color: "white"
|
||||||
|
anchors.top: text1.bottom
|
||||||
|
anchors.topMargin: 5
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 0
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 0
|
||||||
|
font.pixelSize: 12
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
newMaterialDialog.keyboardEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
newMaterialDialog.keyboardEnabled = HMD.active
|
||||||
|
parent.focus = true;
|
||||||
|
parent.forceActiveFocus();
|
||||||
|
materialURL.cursorPosition = materialURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: textInputBox
|
||||||
|
color: "white"
|
||||||
|
anchors.fill: materialURL
|
||||||
|
opacity: 0.1
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: row1
|
||||||
|
height: 400
|
||||||
|
spacing: 30
|
||||||
|
anchors.top: materialURL.bottom
|
||||||
|
anchors.topMargin: 5
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 0
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 0
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: column3
|
||||||
|
height: 400
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
/*Text {
|
||||||
|
id: text3
|
||||||
|
text: qsTr("Material Mode")
|
||||||
|
color: "#ffffff"
|
||||||
|
font.pixelSize: 12
|
||||||
|
}
|
||||||
|
|
||||||
|
ComboBox {
|
||||||
|
id: materialMappingMode
|
||||||
|
property var materialArray: ["UV space material",
|
||||||
|
"3D projected material"]
|
||||||
|
|
||||||
|
width: 200
|
||||||
|
z: 100
|
||||||
|
transformOrigin: Item.Center
|
||||||
|
model: materialArray
|
||||||
|
}*/
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: row3
|
||||||
|
width: 200
|
||||||
|
height: 400
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
anchors.horizontalCenter: column3.horizontalCenter
|
||||||
|
anchors.horizontalCenterOffset: -20
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: button1
|
||||||
|
text: qsTr("Add")
|
||||||
|
z: -1
|
||||||
|
onClicked: {
|
||||||
|
newMaterialDialog.sendToScript({
|
||||||
|
method: "newMaterialDialogAdd",
|
||||||
|
params: {
|
||||||
|
textInput: materialURL.text,
|
||||||
|
//comboBox: materialMappingMode.currentIndex
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: button2
|
||||||
|
z: -1
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
onClicked: {
|
||||||
|
newMaterialDialog.sendToScript({method: "newMaterialDialogCancel"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keyboard {
|
||||||
|
id: keyboard
|
||||||
|
raised: parent.keyboardEnabled
|
||||||
|
numeric: parent.punctuationMode
|
||||||
|
anchors {
|
||||||
|
bottom: parent.bottom
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,6 +66,16 @@ Item {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isUrlLoaded(url) {
|
||||||
|
if (currentApp >= 0) {
|
||||||
|
var currentAppUrl = tabletApps.get(currentApp).appUrl;
|
||||||
|
if (currentAppUrl === url) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function loadSource(url) {
|
function loadSource(url) {
|
||||||
tabletApps.clear();
|
tabletApps.clear();
|
||||||
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
||||||
|
@ -73,15 +83,18 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadQMLOnTop(url) {
|
function loadQMLOnTop(url) {
|
||||||
|
if (!isUrlLoaded(url)) {
|
||||||
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
tabletApps.append({"appUrl": url, "isWebUrl": false, "scriptUrl": "", "appWebUrl": ""});
|
||||||
loader.load(tabletApps.get(currentApp).appUrl, function(){
|
loader.load(tabletApps.get(currentApp).appUrl, function(){
|
||||||
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
if (loader.item.hasOwnProperty("gotoPreviousApp")) {
|
||||||
loader.item.gotoPreviousApp = true;
|
loader.item.gotoPreviousApp = true;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadWebContent(source, url, injectJavaScriptUrl) {
|
function loadWebContent(source, url, injectJavaScriptUrl) {
|
||||||
|
if (!isUrlLoaded(url)) {
|
||||||
tabletApps.append({"appUrl": source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url});
|
tabletApps.append({"appUrl": source, "isWebUrl": true, "scriptUrl": injectJavaScriptUrl, "appWebUrl": url});
|
||||||
loader.load(source, function() {
|
loader.load(source, function() {
|
||||||
loader.item.scriptURL = injectJavaScriptUrl;
|
loader.item.scriptURL = injectJavaScriptUrl;
|
||||||
|
@ -91,6 +104,7 @@ Item {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loadWebBase(url, injectJavaScriptUrl) {
|
function loadWebBase(url, injectJavaScriptUrl) {
|
||||||
loadWebContent("hifi/tablet/TabletWebView.qml", url, injectJavaScriptUrl);
|
loadWebContent("hifi/tablet/TabletWebView.qml", url, injectJavaScriptUrl);
|
||||||
|
|
|
@ -89,6 +89,15 @@ Fadable {
|
||||||
window.shown = value;
|
window.shown = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used to snap window content to pixel by translating content by negative fractional part of the x/y
|
||||||
|
// thus if x was 5.41, snapper's x will be -0.41
|
||||||
|
// avoiding fractional window position is to avoid artifacts in text rendering when the fractional positions are present.
|
||||||
|
transform: Translate {
|
||||||
|
id: snapper
|
||||||
|
x: 0;
|
||||||
|
y: 0;
|
||||||
|
}
|
||||||
|
|
||||||
property var rectifier: Timer {
|
property var rectifier: Timer {
|
||||||
property bool executing: false;
|
property bool executing: false;
|
||||||
interval: 100
|
interval: 100
|
||||||
|
@ -97,8 +106,8 @@ Fadable {
|
||||||
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
executing = true;
|
executing = true;
|
||||||
x = Math.floor(x);
|
snapper.x = Math.floor(x) - x;
|
||||||
y = Math.floor(y);
|
snapper.y = Math.floor(y) - y;
|
||||||
executing = false;
|
executing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1593,6 +1593,73 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
EntityTree::setAddMaterialToEntityOperator([&](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
// try to find the renderable
|
||||||
|
auto renderable = getEntities()->renderableForEntityId(entityID);
|
||||||
|
if (renderable) {
|
||||||
|
renderable->addMaterial(material, parentMaterialName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// even if we don't find it, try to find the entity
|
||||||
|
auto entity = getEntities()->getEntity(entityID);
|
||||||
|
if (entity) {
|
||||||
|
entity->addMaterial(material, parentMaterialName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
EntityTree::setRemoveMaterialFromEntityOperator([&](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
// try to find the renderable
|
||||||
|
auto renderable = getEntities()->renderableForEntityId(entityID);
|
||||||
|
if (renderable) {
|
||||||
|
renderable->removeMaterial(material, parentMaterialName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// even if we don't find it, try to find the entity
|
||||||
|
auto entity = getEntities()->getEntity(entityID);
|
||||||
|
if (entity) {
|
||||||
|
entity->removeMaterial(material, parentMaterialName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||||
|
auto avatar = avatarManager->getAvatarBySessionID(avatarID);
|
||||||
|
if (avatar) {
|
||||||
|
avatar->addMaterial(material, parentMaterialName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||||
|
auto avatar = avatarManager->getAvatarBySessionID(avatarID);
|
||||||
|
if (avatar) {
|
||||||
|
avatar->removeMaterial(material, parentMaterialName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
auto overlay = _overlays.getOverlay(overlayID);
|
||||||
|
if (overlay) {
|
||||||
|
overlay->addMaterial(material, parentMaterialName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
auto overlay = _overlays.getOverlay(overlayID);
|
||||||
|
if (overlay) {
|
||||||
|
overlay->removeMaterial(material, parentMaterialName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
// Keyboard focus handling for Web overlays.
|
// Keyboard focus handling for Web overlays.
|
||||||
auto overlays = &(qApp->getOverlays());
|
auto overlays = &(qApp->getOverlays());
|
||||||
connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) {
|
connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) {
|
||||||
|
|
|
@ -120,16 +120,19 @@ QScriptValue WindowScriptingInterface::confirm(const QString& message) {
|
||||||
/// \param const QString& defaultText default text in the text box
|
/// \param const QString& defaultText default text in the text box
|
||||||
/// \return QScriptValue string text value in text box if the dialog was accepted, `null` otherwise.
|
/// \return QScriptValue string text value in text box if the dialog was accepted, `null` otherwise.
|
||||||
QScriptValue WindowScriptingInterface::prompt(const QString& message, const QString& defaultText) {
|
QScriptValue WindowScriptingInterface::prompt(const QString& message, const QString& defaultText) {
|
||||||
bool ok = false;
|
QString result = OffscreenUi::getText(nullptr, "", message, QLineEdit::Normal, defaultText);
|
||||||
QString result = OffscreenUi::getText(nullptr, "", message, QLineEdit::Normal, defaultText, &ok);
|
if (QScriptValue(result).equals("")) {
|
||||||
return ok ? QScriptValue(result) : QScriptValue::NullValue;
|
return QScriptValue::NullValue;
|
||||||
|
}
|
||||||
|
return QScriptValue(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display a prompt with a text box
|
/// Display a prompt with a text box
|
||||||
/// \param const QString& message message to display
|
/// \param const QString& message message to display
|
||||||
/// \param const QString& defaultText default text in the text box
|
/// \param const QString& defaultText default text in the text box
|
||||||
void WindowScriptingInterface::promptAsync(const QString& message, const QString& defaultText) {
|
void WindowScriptingInterface::promptAsync(const QString& message, const QString& defaultText) {
|
||||||
ModalDialogListener* dlg = OffscreenUi::getTextAsync(nullptr, "", message, QLineEdit::Normal, defaultText);
|
bool ok = false;
|
||||||
|
ModalDialogListener* dlg = OffscreenUi::getTextAsync(nullptr, "", message, QLineEdit::Normal, defaultText, &ok);
|
||||||
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant result) {
|
connect(dlg, &ModalDialogListener::response, this, [=] (QVariant result) {
|
||||||
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
disconnect(dlg, &ModalDialogListener::response, this, nullptr);
|
||||||
emit promptTextChanged(result.toString());
|
emit promptTextChanged(result.toString());
|
||||||
|
|
|
@ -83,6 +83,7 @@ void ModelOverlay::update(float deltatime) {
|
||||||
auto modelOverlay = static_cast<ModelOverlay*>(&data);
|
auto modelOverlay = static_cast<ModelOverlay*>(&data);
|
||||||
modelOverlay->setSubRenderItemIDs(newRenderItemIDs);
|
modelOverlay->setSubRenderItemIDs(newRenderItemIDs);
|
||||||
});
|
});
|
||||||
|
processMaterials();
|
||||||
}
|
}
|
||||||
if (_visibleDirty) {
|
if (_visibleDirty) {
|
||||||
_visibleDirty = false;
|
_visibleDirty = false;
|
||||||
|
@ -108,6 +109,7 @@ void ModelOverlay::update(float deltatime) {
|
||||||
bool ModelOverlay::addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) {
|
bool ModelOverlay::addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) {
|
||||||
Volume3DOverlay::addToScene(overlay, scene, transaction);
|
Volume3DOverlay::addToScene(overlay, scene, transaction);
|
||||||
_model->addToScene(scene, transaction);
|
_model->addToScene(scene, transaction);
|
||||||
|
processMaterials();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,3 +634,29 @@ uint32_t ModelOverlay::fetchMetaSubItems(render::ItemIDs& subItems) const {
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelOverlay::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
Overlay::addMaterial(material, parentMaterialName);
|
||||||
|
if (_model && _model->fetchRenderItemIDs().size() > 0) {
|
||||||
|
_model->addMaterial(material, parentMaterialName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelOverlay::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
Overlay::removeMaterial(material, parentMaterialName);
|
||||||
|
if (_model && _model->fetchRenderItemIDs().size() > 0) {
|
||||||
|
_model->removeMaterial(material, parentMaterialName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelOverlay::processMaterials() {
|
||||||
|
assert(_model);
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
for (auto& shapeMaterialPair : _materials) {
|
||||||
|
auto material = shapeMaterialPair.second;
|
||||||
|
while (!material.empty()) {
|
||||||
|
_model->addMaterial(material.top(), shapeMaterialPair.first);
|
||||||
|
material.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,6 +59,9 @@ public:
|
||||||
void setDrawInFront(bool drawInFront) override;
|
void setDrawInFront(bool drawInFront) override;
|
||||||
void setDrawHUDLayer(bool drawHUDLayer) override;
|
void setDrawHUDLayer(bool drawHUDLayer) override;
|
||||||
|
|
||||||
|
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
|
||||||
|
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Transform evalRenderTransform() override;
|
Transform evalRenderTransform() override;
|
||||||
|
|
||||||
|
@ -110,6 +113,8 @@ private:
|
||||||
bool _drawInFrontDirty { false };
|
bool _drawInFrontDirty { false };
|
||||||
bool _drawInHUDDirty { false };
|
bool _drawInHUDDirty { false };
|
||||||
|
|
||||||
|
void processMaterials();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ModelOverlay_h
|
#endif // hifi_ModelOverlay_h
|
||||||
|
|
|
@ -235,3 +235,13 @@ QVector<OverlayID> qVectorOverlayIDFromScriptValue(const QScriptValue& array) {
|
||||||
}
|
}
|
||||||
return newVector;
|
return newVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Overlay::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
_materials[parentMaterialName].push(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Overlay::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
_materials[parentMaterialName].remove(material);
|
||||||
|
}
|
|
@ -91,6 +91,9 @@ public:
|
||||||
unsigned int getStackOrder() const { return _stackOrder; }
|
unsigned int getStackOrder() const { return _stackOrder; }
|
||||||
void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; }
|
void setStackOrder(unsigned int stackOrder) { _stackOrder = stackOrder; }
|
||||||
|
|
||||||
|
virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||||
|
virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float updatePulse();
|
float updatePulse();
|
||||||
|
|
||||||
|
@ -117,6 +120,9 @@ protected:
|
||||||
static const xColor DEFAULT_OVERLAY_COLOR;
|
static const xColor DEFAULT_OVERLAY_COLOR;
|
||||||
static const float DEFAULT_ALPHA;
|
static const float DEFAULT_ALPHA;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
|
||||||
|
std::mutex _materialsLock;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OverlayID _overlayID; // only used for non-3d overlays
|
OverlayID _overlayID; // only used for non-3d overlays
|
||||||
};
|
};
|
||||||
|
|
|
@ -219,7 +219,7 @@ void Avatar::updateAvatarEntities() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getID() == QUuid()) {
|
if (getID() == QUuid() || getID() == AVATAR_SELF_ID) {
|
||||||
return; // wait until MyAvatar gets an ID before doing this.
|
return; // wait until MyAvatar gets an ID before doing this.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,6 +570,7 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc
|
||||||
}
|
}
|
||||||
transaction.resetItem(_renderItemID, avatarPayloadPointer);
|
transaction.resetItem(_renderItemID, avatarPayloadPointer);
|
||||||
_skeletonModel->addToScene(scene, transaction);
|
_skeletonModel->addToScene(scene, transaction);
|
||||||
|
processMaterials();
|
||||||
for (auto& attachmentModel : _attachmentModels) {
|
for (auto& attachmentModel : _attachmentModels) {
|
||||||
attachmentModel->addToScene(scene, transaction);
|
attachmentModel->addToScene(scene, transaction);
|
||||||
}
|
}
|
||||||
|
@ -761,6 +762,7 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
|
||||||
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
|
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
|
||||||
_skeletonModel->removeFromScene(scene, transaction);
|
_skeletonModel->removeFromScene(scene, transaction);
|
||||||
_skeletonModel->addToScene(scene, transaction);
|
_skeletonModel->addToScene(scene, transaction);
|
||||||
|
processMaterials();
|
||||||
canTryFade = true;
|
canTryFade = true;
|
||||||
_isAnimatingScale = true;
|
_isAnimatingScale = true;
|
||||||
}
|
}
|
||||||
|
@ -1760,3 +1762,31 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const {
|
||||||
return DEFAULT_AVATAR_EYE_HEIGHT;
|
return DEFAULT_AVATAR_EYE_HEIGHT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Avatar::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
_materials[parentMaterialName].push(material);
|
||||||
|
if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) {
|
||||||
|
_skeletonModel->addMaterial(material, parentMaterialName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Avatar::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
_materials[parentMaterialName].remove(material);
|
||||||
|
if (_skeletonModel && _skeletonModel->fetchRenderItemIDs().size() > 0) {
|
||||||
|
_skeletonModel->removeMaterial(material, parentMaterialName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Avatar::processMaterials() {
|
||||||
|
assert(_skeletonModel);
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
for (auto& shapeMaterialPair : _materials) {
|
||||||
|
auto material = shapeMaterialPair.second;
|
||||||
|
while (!material.empty()) {
|
||||||
|
_skeletonModel->addMaterial(material.top(), shapeMaterialPair.first);
|
||||||
|
material.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -272,6 +272,9 @@ public:
|
||||||
|
|
||||||
virtual void setAvatarEntityDataChanged(bool value) override;
|
virtual void setAvatarEntityDataChanged(bool value) override;
|
||||||
|
|
||||||
|
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
|
||||||
|
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
// FIXME - these should be migrated to use Pose data instead
|
// FIXME - these should be migrated to use Pose data instead
|
||||||
|
@ -397,6 +400,11 @@ protected:
|
||||||
float _displayNameAlpha { 1.0f };
|
float _displayNameAlpha { 1.0f };
|
||||||
|
|
||||||
ThreadSafeValueCache<float> _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT };
|
ThreadSafeValueCache<float> _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT };
|
||||||
|
|
||||||
|
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
|
||||||
|
std::mutex _materialsLock;
|
||||||
|
|
||||||
|
void processMaterials();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Avatar_h
|
#endif // hifi_Avatar_h
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
set(TARGET_NAME avatars)
|
set(TARGET_NAME avatars)
|
||||||
setup_hifi_library(Network Script)
|
setup_hifi_library(Network Script)
|
||||||
link_hifi_libraries(shared networking)
|
include_hifi_library_headers(gpu)
|
||||||
|
link_hifi_libraries(shared networking graphics)
|
||||||
|
|
|
@ -54,6 +54,8 @@
|
||||||
#include "HeadData.h"
|
#include "HeadData.h"
|
||||||
#include "PathUtils.h"
|
#include "PathUtils.h"
|
||||||
|
|
||||||
|
#include <graphics/Material.h>
|
||||||
|
|
||||||
using AvatarSharedPointer = std::shared_ptr<AvatarData>;
|
using AvatarSharedPointer = std::shared_ptr<AvatarData>;
|
||||||
using AvatarWeakPointer = std::weak_ptr<AvatarData>;
|
using AvatarWeakPointer = std::weak_ptr<AvatarData>;
|
||||||
using AvatarHash = QHash<QUuid, AvatarSharedPointer>;
|
using AvatarHash = QHash<QUuid, AvatarSharedPointer>;
|
||||||
|
@ -694,6 +696,9 @@ public:
|
||||||
|
|
||||||
bool getIsReplicated() const { return _isReplicated; }
|
bool getIsReplicated() const { return _isReplicated; }
|
||||||
|
|
||||||
|
virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {}
|
||||||
|
virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void displayNameChanged();
|
void displayNameChanged();
|
||||||
void sessionDisplayNameChanged();
|
void sessionDisplayNameChanged();
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "RenderableTextEntityItem.h"
|
#include "RenderableTextEntityItem.h"
|
||||||
#include "RenderableWebEntityItem.h"
|
#include "RenderableWebEntityItem.h"
|
||||||
#include "RenderableZoneEntityItem.h"
|
#include "RenderableZoneEntityItem.h"
|
||||||
|
#include "RenderableMaterialEntityItem.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
@ -145,6 +146,7 @@ EntityRenderer::EntityRenderer(const EntityItemPointer& entity) : _entity(entity
|
||||||
_needsRenderUpdate = true;
|
_needsRenderUpdate = true;
|
||||||
emit requestRenderUpdate();
|
emit requestRenderUpdate();
|
||||||
});
|
});
|
||||||
|
_materials = entity->getMaterials();
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityRenderer::~EntityRenderer() { }
|
EntityRenderer::~EntityRenderer() { }
|
||||||
|
@ -252,6 +254,10 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer,
|
||||||
result = make_renderer<ZoneEntityRenderer>(entity);
|
result = make_renderer<ZoneEntityRenderer>(entity);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type::Material:
|
||||||
|
result = make_renderer<MaterialEntityRenderer>(entity);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -395,3 +401,13 @@ void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) {
|
||||||
entity->deregisterChangeHandler(_changeHandlerId);
|
entity->deregisterChangeHandler(_changeHandlerId);
|
||||||
QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr);
|
QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityRenderer::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
_materials[parentMaterialName].push(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityRenderer::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
_materials[parentMaterialName].remove(material);
|
||||||
|
}
|
|
@ -54,12 +54,14 @@ public:
|
||||||
|
|
||||||
const uint64_t& getUpdateTime() const { return _updateTime; }
|
const uint64_t& getUpdateTime() const { return _updateTime; }
|
||||||
|
|
||||||
|
virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||||
|
virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
|
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
|
||||||
virtual void onAddToScene(const EntityItemPointer& entity);
|
virtual void onAddToScene(const EntityItemPointer& entity);
|
||||||
virtual void onRemoveFromScene(const EntityItemPointer& entity);
|
virtual void onRemoveFromScene(const EntityItemPointer& entity);
|
||||||
|
|
||||||
protected:
|
|
||||||
EntityRenderer(const EntityItemPointer& entity);
|
EntityRenderer(const EntityItemPointer& entity);
|
||||||
~EntityRenderer();
|
~EntityRenderer();
|
||||||
|
|
||||||
|
@ -130,6 +132,8 @@ protected:
|
||||||
// Only touched on the rendering thread
|
// Only touched on the rendering thread
|
||||||
bool _renderUpdateQueued{ false };
|
bool _renderUpdateQueued{ false };
|
||||||
|
|
||||||
|
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
|
||||||
|
std::mutex _materialsLock;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The base class relies on comparing the model transform to the entity transform in order
|
// The base class relies on comparing the model transform to the entity transform in order
|
||||||
|
|
269
libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
Normal file
269
libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 1/18/2018
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "RenderableMaterialEntityItem.h"
|
||||||
|
|
||||||
|
#include "RenderPipelines.h"
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
using namespace render::entities;
|
||||||
|
|
||||||
|
bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
|
||||||
|
if (entity->getMaterial() != _drawMaterial) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (entity->getParentID() != _parentID || entity->getClientOnly() != _clientOnly || entity->getOwningAvatarID() != _owningAvatarID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
|
||||||
|
withWriteLock([&] {
|
||||||
|
_drawMaterial = entity->getMaterial();
|
||||||
|
_parentID = entity->getParentID();
|
||||||
|
_clientOnly = entity->getClientOnly();
|
||||||
|
_owningAvatarID = entity->getOwningAvatarID();
|
||||||
|
_materialMappingPos = entity->getMaterialMappingPos();
|
||||||
|
_materialMappingScale = entity->getMaterialMappingScale();
|
||||||
|
_materialMappingRot = entity->getMaterialMappingRot();
|
||||||
|
_renderTransform = getModelTransform();
|
||||||
|
const float MATERIAL_ENTITY_SCALE = 0.5f;
|
||||||
|
_renderTransform.postScale(MATERIAL_ENTITY_SCALE);
|
||||||
|
_renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemKey MaterialEntityRenderer::getKey() {
|
||||||
|
ItemKey::Builder builder;
|
||||||
|
builder.withTypeShape().withTagBits(render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1);
|
||||||
|
|
||||||
|
if (!_visible) {
|
||||||
|
builder.withInvisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_drawMaterial) {
|
||||||
|
auto matKey = _drawMaterial->getKey();
|
||||||
|
if (matKey.isTranslucent()) {
|
||||||
|
builder.withTransparent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapeKey MaterialEntityRenderer::getShapeKey() {
|
||||||
|
graphics::MaterialKey drawMaterialKey;
|
||||||
|
if (_drawMaterial) {
|
||||||
|
drawMaterialKey = _drawMaterial->getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||||
|
bool hasTangents = drawMaterialKey.isNormalMap();
|
||||||
|
bool hasSpecular = drawMaterialKey.isMetallicMap();
|
||||||
|
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
||||||
|
bool isUnlit = drawMaterialKey.isUnlit();
|
||||||
|
|
||||||
|
ShapeKey::Builder builder;
|
||||||
|
builder.withMaterial();
|
||||||
|
|
||||||
|
if (isTranslucent) {
|
||||||
|
builder.withTranslucent();
|
||||||
|
}
|
||||||
|
if (hasTangents) {
|
||||||
|
builder.withTangents();
|
||||||
|
}
|
||||||
|
if (hasSpecular) {
|
||||||
|
builder.withSpecular();
|
||||||
|
}
|
||||||
|
if (hasLightmap) {
|
||||||
|
builder.withLightmap();
|
||||||
|
}
|
||||||
|
if (isUnlit) {
|
||||||
|
builder.withUnlit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) {
|
||||||
|
return glm::vec3(glm::sin(theta) * glm::cos(phi), glm::cos(theta), glm::sin(theta) * glm::sin(phi));
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) {
|
||||||
|
return glm::vec3(-glm::cos(theta) * glm::cos(phi), glm::sin(theta), -glm::cos(theta) * glm::sin(phi));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityRenderer::addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) {
|
||||||
|
buffer.push_back(pos.x); buffer.push_back(pos.y); buffer.push_back(pos.z);
|
||||||
|
buffer.push_back(tan.x); buffer.push_back(tan.y); buffer.push_back(tan.z);
|
||||||
|
buffer.push_back(uv.x); buffer.push_back(uv.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityRenderer::addTriangleFan(std::vector<float>& buffer, int stack, int step) {
|
||||||
|
float v1 = ((float)stack) / STACKS;
|
||||||
|
float theta1 = v1 * (float)M_PI;
|
||||||
|
glm::vec3 tip = getVertexPos(0, theta1);
|
||||||
|
float v2 = ((float)(stack + step)) / STACKS;
|
||||||
|
float theta2 = v2 * (float)M_PI;
|
||||||
|
for (int i = 0; i < SLICES; i++) {
|
||||||
|
float u1 = ((float)i) / SLICES;
|
||||||
|
float u2 = ((float)(i + step)) / SLICES;
|
||||||
|
float phi1 = u1 * M_PI_TIMES_2;
|
||||||
|
float phi2 = u2 * M_PI_TIMES_2;
|
||||||
|
/* (flipped for negative step)
|
||||||
|
p1
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
p3 ------ p2
|
||||||
|
*/
|
||||||
|
|
||||||
|
glm::vec3 pos2 = getVertexPos(phi2, theta2);
|
||||||
|
glm::vec3 pos3 = getVertexPos(phi1, theta2);
|
||||||
|
|
||||||
|
glm::vec3 tan1 = getTangent(0, theta1);
|
||||||
|
glm::vec3 tan2 = getTangent(phi2, theta2);
|
||||||
|
glm::vec3 tan3 = getTangent(phi1, theta2);
|
||||||
|
|
||||||
|
glm::vec2 uv1 = glm::vec2((u1 + u2) / 2.0f, v1);
|
||||||
|
glm::vec2 uv2 = glm::vec2(u2, v2);
|
||||||
|
glm::vec2 uv3 = glm::vec2(u1, v2);
|
||||||
|
|
||||||
|
addVertex(buffer, tip, tan1, uv1);
|
||||||
|
addVertex(buffer, pos2, tan2, uv2);
|
||||||
|
addVertex(buffer, pos3, tan3, uv3);
|
||||||
|
|
||||||
|
_numVertices += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MaterialEntityRenderer::_numVertices = 0;
|
||||||
|
std::shared_ptr<gpu::Stream::Format> MaterialEntityRenderer::_streamFormat = nullptr;
|
||||||
|
std::shared_ptr<gpu::BufferStream> MaterialEntityRenderer::_stream = nullptr;
|
||||||
|
std::shared_ptr<gpu::Buffer> MaterialEntityRenderer::_verticesBuffer = nullptr;
|
||||||
|
|
||||||
|
void MaterialEntityRenderer::generateMesh() {
|
||||||
|
_streamFormat = std::make_shared<gpu::Stream::Format>();
|
||||||
|
_stream = std::make_shared<gpu::BufferStream>();
|
||||||
|
_verticesBuffer = std::make_shared<gpu::Buffer>();
|
||||||
|
|
||||||
|
const int NUM_POS_COORDS = 3;
|
||||||
|
const int NUM_TANGENT_COORDS = 3;
|
||||||
|
const int VERTEX_TANGENT_OFFSET = NUM_POS_COORDS * sizeof(float);
|
||||||
|
const int VERTEX_TEXCOORD_OFFSET = VERTEX_TANGENT_OFFSET + NUM_TANGENT_COORDS * sizeof(float);
|
||||||
|
|
||||||
|
_streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||||
|
_streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
|
||||||
|
_streamFormat->setAttribute(gpu::Stream::TANGENT, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_TANGENT_OFFSET);
|
||||||
|
_streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET);
|
||||||
|
|
||||||
|
_stream->addBuffer(_verticesBuffer, 0, _streamFormat->getChannels().at(0)._stride);
|
||||||
|
|
||||||
|
std::vector<float> vertexBuffer;
|
||||||
|
|
||||||
|
// Top
|
||||||
|
addTriangleFan(vertexBuffer, 0, 1);
|
||||||
|
|
||||||
|
// Middle section
|
||||||
|
for (int j = 1; j < STACKS - 1; j++) {
|
||||||
|
float v1 = ((float)j) / STACKS;
|
||||||
|
float v2 = ((float)(j + 1)) / STACKS;
|
||||||
|
float theta1 = v1 * (float)M_PI;
|
||||||
|
float theta2 = v2 * (float)M_PI;
|
||||||
|
for (int i = 0; i < SLICES; i++) {
|
||||||
|
float u1 = ((float)i) / SLICES;
|
||||||
|
float u2 = ((float)(i + 1)) / SLICES;
|
||||||
|
float phi1 = u1 * M_PI_TIMES_2;
|
||||||
|
float phi2 = u2 * M_PI_TIMES_2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
p2 ---- p3
|
||||||
|
| / |
|
||||||
|
| / |
|
||||||
|
| / |
|
||||||
|
p1 ---- p4
|
||||||
|
*/
|
||||||
|
|
||||||
|
glm::vec3 pos1 = getVertexPos(phi1, theta2);
|
||||||
|
glm::vec3 pos2 = getVertexPos(phi1, theta1);
|
||||||
|
glm::vec3 pos3 = getVertexPos(phi2, theta1);
|
||||||
|
glm::vec3 pos4 = getVertexPos(phi2, theta2);
|
||||||
|
|
||||||
|
glm::vec3 tan1 = getTangent(phi1, theta2);
|
||||||
|
glm::vec3 tan2 = getTangent(phi1, theta1);
|
||||||
|
glm::vec3 tan3 = getTangent(phi2, theta1);
|
||||||
|
glm::vec3 tan4 = getTangent(phi2, theta2);
|
||||||
|
|
||||||
|
glm::vec2 uv1 = glm::vec2(u1, v2);
|
||||||
|
glm::vec2 uv2 = glm::vec2(u1, v1);
|
||||||
|
glm::vec2 uv3 = glm::vec2(u2, v1);
|
||||||
|
glm::vec2 uv4 = glm::vec2(u2, v2);
|
||||||
|
|
||||||
|
addVertex(vertexBuffer, pos1, tan1, uv1);
|
||||||
|
addVertex(vertexBuffer, pos2, tan2, uv2);
|
||||||
|
addVertex(vertexBuffer, pos3, tan3, uv3);
|
||||||
|
|
||||||
|
addVertex(vertexBuffer, pos3, tan3, uv3);
|
||||||
|
addVertex(vertexBuffer, pos4, tan4, uv4);
|
||||||
|
addVertex(vertexBuffer, pos1, tan1, uv1);
|
||||||
|
|
||||||
|
_numVertices += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom
|
||||||
|
addTriangleFan(vertexBuffer, STACKS, -1);
|
||||||
|
|
||||||
|
_verticesBuffer->append(vertexBuffer.size() * sizeof(float), (gpu::Byte*) vertexBuffer.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityRenderer::doRender(RenderArgs* args) {
|
||||||
|
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
|
||||||
|
Q_ASSERT(args->_batch);
|
||||||
|
gpu::Batch& batch = *args->_batch;
|
||||||
|
|
||||||
|
// Don't render if our parent is set or our material is null
|
||||||
|
QUuid parentID;
|
||||||
|
Transform renderTransform;
|
||||||
|
graphics::MaterialPointer drawMaterial;
|
||||||
|
Transform textureTransform;
|
||||||
|
withReadLock([&] {
|
||||||
|
parentID = _clientOnly ? _owningAvatarID : _parentID;
|
||||||
|
renderTransform = _renderTransform;
|
||||||
|
drawMaterial = _drawMaterial;
|
||||||
|
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
|
||||||
|
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
|
||||||
|
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
|
||||||
|
});
|
||||||
|
if (!parentID.isNull() || !drawMaterial) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
batch.setModelTransform(renderTransform);
|
||||||
|
drawMaterial->setTextureTransforms(textureTransform);
|
||||||
|
|
||||||
|
// bind the material
|
||||||
|
RenderPipelines::bindMaterial(drawMaterial, batch, args->_enableTexturing);
|
||||||
|
args->_details._materialSwitches++;
|
||||||
|
|
||||||
|
// Draw!
|
||||||
|
if (_numVertices == 0) {
|
||||||
|
generateMesh();
|
||||||
|
}
|
||||||
|
|
||||||
|
batch.setInputFormat(_streamFormat);
|
||||||
|
batch.setInputStream(0, *_stream);
|
||||||
|
batch.draw(gpu::TRIANGLES, _numVertices, 0);
|
||||||
|
|
||||||
|
const int NUM_VERTICES_PER_TRIANGLE = 3;
|
||||||
|
args->_details._trianglesRendered += _numVertices / NUM_VERTICES_PER_TRIANGLE;
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 1/18/2018
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_RenderableMaterialEntityItem_h
|
||||||
|
#define hifi_RenderableMaterialEntityItem_h
|
||||||
|
|
||||||
|
#include "RenderableEntityItem.h"
|
||||||
|
|
||||||
|
#include <MaterialEntityItem.h>
|
||||||
|
|
||||||
|
class NetworkMaterial;
|
||||||
|
|
||||||
|
namespace render { namespace entities {
|
||||||
|
|
||||||
|
class MaterialEntityRenderer : public TypedEntityRenderer<MaterialEntityItem> {
|
||||||
|
using Parent = TypedEntityRenderer<MaterialEntityItem>;
|
||||||
|
using Pointer = std::shared_ptr<MaterialEntityRenderer>;
|
||||||
|
public:
|
||||||
|
MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
|
||||||
|
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
|
||||||
|
virtual void doRender(RenderArgs* args) override;
|
||||||
|
|
||||||
|
ItemKey getKey() override;
|
||||||
|
ShapeKey getShapeKey() override;
|
||||||
|
|
||||||
|
QUuid _parentID;
|
||||||
|
bool _clientOnly;
|
||||||
|
QUuid _owningAvatarID;
|
||||||
|
glm::vec2 _materialMappingPos;
|
||||||
|
glm::vec2 _materialMappingScale;
|
||||||
|
float _materialMappingRot;
|
||||||
|
Transform _renderTransform;
|
||||||
|
|
||||||
|
std::shared_ptr<NetworkMaterial> _drawMaterial;
|
||||||
|
|
||||||
|
static int _numVertices;
|
||||||
|
static std::shared_ptr<gpu::Stream::Format> _streamFormat;
|
||||||
|
static std::shared_ptr<gpu::BufferStream> _stream;
|
||||||
|
static std::shared_ptr<gpu::Buffer> _verticesBuffer;
|
||||||
|
|
||||||
|
void generateMesh();
|
||||||
|
void addTriangleFan(std::vector<float>& buffer, int stack, int step);
|
||||||
|
static glm::vec3 getVertexPos(float phi, float theta);
|
||||||
|
static glm::vec3 getTangent(float phi, float theta);
|
||||||
|
static void addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv);
|
||||||
|
const int SLICES = 15;
|
||||||
|
const int STACKS = 9;
|
||||||
|
const float M_PI_TIMES_2 = 2.0f * (float)M_PI;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
||||||
|
#endif // hifi_RenderableMaterialEntityItem_h
|
|
@ -1389,6 +1389,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
auto entityRenderer = static_cast<EntityRenderer*>(&data);
|
auto entityRenderer = static_cast<EntityRenderer*>(&data);
|
||||||
entityRenderer->setSubRenderItemIDs(newRenderItemIDs);
|
entityRenderer->setSubRenderItemIDs(newRenderItemIDs);
|
||||||
});
|
});
|
||||||
|
processMaterials();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,3 +1476,28 @@ void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelEntityRenderer::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
Parent::addMaterial(material, parentMaterialName);
|
||||||
|
if (_model && _model->fetchRenderItemIDs().size() > 0) {
|
||||||
|
_model->addMaterial(material, parentMaterialName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelEntityRenderer::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
Parent::removeMaterial(material, parentMaterialName);
|
||||||
|
if (_model && _model->fetchRenderItemIDs().size() > 0) {
|
||||||
|
_model->removeMaterial(material, parentMaterialName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelEntityRenderer::processMaterials() {
|
||||||
|
assert(_model);
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
for (auto& shapeMaterialPair : _materials) {
|
||||||
|
auto material = shapeMaterialPair.second;
|
||||||
|
while (!material.empty()) {
|
||||||
|
_model->addMaterial(material.top(), shapeMaterialPair.first);
|
||||||
|
material.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -138,10 +138,14 @@ namespace render { namespace entities {
|
||||||
class ModelEntityRenderer : public TypedEntityRenderer<RenderableModelEntityItem> {
|
class ModelEntityRenderer : public TypedEntityRenderer<RenderableModelEntityItem> {
|
||||||
using Parent = TypedEntityRenderer<RenderableModelEntityItem>;
|
using Parent = TypedEntityRenderer<RenderableModelEntityItem>;
|
||||||
friend class EntityRenderer;
|
friend class EntityRenderer;
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ModelEntityRenderer(const EntityItemPointer& entity);
|
ModelEntityRenderer(const EntityItemPointer& entity);
|
||||||
|
|
||||||
|
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
|
||||||
|
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
|
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
|
||||||
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
|
virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override;
|
||||||
|
@ -194,6 +198,8 @@ private:
|
||||||
uint64_t _lastAnimated { 0 };
|
uint64_t _lastAnimated { 0 };
|
||||||
|
|
||||||
render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
|
render::ItemKey _itemKey { render::ItemKey::Builder().withTypeMeta() };
|
||||||
|
|
||||||
|
void processMaterials();
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // namespace
|
} } // namespace
|
||||||
|
|
|
@ -54,8 +54,7 @@ bool ShapeEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
|
||||||
if (_lastUserData != entity->getUserData()) {
|
if (_lastUserData != entity->getUserData()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
glm::vec4 newColor(toGlm(entity->getXColor()), entity->getLocalRenderAlpha());
|
if (_material != entity->getMaterial()) {
|
||||||
if (newColor != _color) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +77,9 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
||||||
_procedural.setProceduralData(ProceduralData::parse(_lastUserData));
|
_procedural.setProceduralData(ProceduralData::parse(_lastUserData));
|
||||||
}
|
}
|
||||||
|
|
||||||
_color = vec4(toGlm(entity->getXColor()), entity->getLocalRenderAlpha());
|
removeMaterial(_material, "0");
|
||||||
|
_material = entity->getMaterial();
|
||||||
|
addMaterial(graphics::MaterialLayer(_material, 0), "0");
|
||||||
|
|
||||||
_shape = entity->getShape();
|
_shape = entity->getShape();
|
||||||
_position = entity->getWorldPosition();
|
_position = entity->getWorldPosition();
|
||||||
|
@ -112,14 +113,13 @@ bool ShapeEntityRenderer::isTransparent() const {
|
||||||
return Parent::isTransparent();
|
return Parent::isTransparent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||||
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
|
PerformanceTimer perfTimer("RenderableShapeEntityItem::render");
|
||||||
Q_ASSERT(args->_batch);
|
Q_ASSERT(args->_batch);
|
||||||
|
|
||||||
gpu::Batch& batch = *args->_batch;
|
gpu::Batch& batch = *args->_batch;
|
||||||
|
|
||||||
|
std::shared_ptr<graphics::Material> mat;
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
GeometryCache::Shape geometryShape;
|
GeometryCache::Shape geometryShape;
|
||||||
bool proceduralRender = false;
|
bool proceduralRender = false;
|
||||||
|
@ -127,15 +127,22 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
|
||||||
withReadLock([&] {
|
withReadLock([&] {
|
||||||
geometryShape = geometryCache->getShapeForEntityShape(_shape);
|
geometryShape = geometryCache->getShapeForEntityShape(_shape);
|
||||||
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
|
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
|
||||||
outColor = _color;
|
mat = _materials["0"].top().material;
|
||||||
|
if (mat) {
|
||||||
|
outColor = glm::vec4(mat->getAlbedo(), mat->getOpacity());
|
||||||
if (_procedural.isReady()) {
|
if (_procedural.isReady()) {
|
||||||
_procedural.prepare(batch, _position, _dimensions, _orientation);
|
_procedural.prepare(batch, _position, _dimensions, _orientation);
|
||||||
outColor = _procedural.getColor(_color);
|
outColor = _procedural.getColor(outColor);
|
||||||
outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f;
|
outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f;
|
||||||
proceduralRender = true;
|
proceduralRender = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!mat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (proceduralRender) {
|
if (proceduralRender) {
|
||||||
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
|
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
|
||||||
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
geometryCache->renderWireShape(batch, geometryShape, outColor);
|
||||||
|
|
|
@ -34,7 +34,7 @@ private:
|
||||||
QString _lastUserData;
|
QString _lastUserData;
|
||||||
Transform _renderTransform;
|
Transform _renderTransform;
|
||||||
entity::Shape _shape { entity::Sphere };
|
entity::Shape _shape { entity::Sphere };
|
||||||
glm::vec4 _color;
|
std::shared_ptr<graphics::Material> _material;
|
||||||
glm::vec3 _position;
|
glm::vec3 _position;
|
||||||
glm::vec3 _dimensions;
|
glm::vec3 _dimensions;
|
||||||
glm::quat _orientation;
|
glm::quat _orientation;
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
set(TARGET_NAME entities)
|
set(TARGET_NAME entities)
|
||||||
setup_hifi_library(Network Script)
|
setup_hifi_library(Network Script)
|
||||||
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
||||||
link_hifi_libraries(shared networking octree avatars graphics)
|
include_hifi_library_headers(fbx)
|
||||||
|
include_hifi_library_headers(gpu)
|
||||||
|
include_hifi_library_headers(image)
|
||||||
|
include_hifi_library_headers(ktx)
|
||||||
|
link_hifi_libraries(shared networking octree avatars graphics model-networking)
|
|
@ -93,7 +93,7 @@ bool DeleteEntityOperator::preRecursion(const OctreeElementPointer& element) {
|
||||||
// and we can stop searching.
|
// and we can stop searching.
|
||||||
if (entityTreeElement == details.containingElement) {
|
if (entityTreeElement == details.containingElement) {
|
||||||
EntityItemPointer theEntity = details.entity;
|
EntityItemPointer theEntity = details.entity;
|
||||||
bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element
|
bool entityDeleted = entityTreeElement->removeEntityItem(theEntity, true); // remove it from the element
|
||||||
assert(entityDeleted);
|
assert(entityDeleted);
|
||||||
(void)entityDeleted; // quite warning
|
(void)entityDeleted; // quite warning
|
||||||
_tree->clearEntityMapEntry(details.entity->getEntityItemID());
|
_tree->clearEntityMapEntry(details.entity->getEntityItemID());
|
||||||
|
|
|
@ -60,14 +60,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItem::~EntityItem() {
|
EntityItem::~EntityItem() {
|
||||||
// clear out any left-over actions
|
|
||||||
EntityTreeElementPointer element = _element; // use local copy of _element for logic below
|
|
||||||
EntityTreePointer entityTree = element ? element->getTree() : nullptr;
|
|
||||||
EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr;
|
|
||||||
if (simulation) {
|
|
||||||
clearActions(simulation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// these pointers MUST be correct at delete, else we probably have a dangling backpointer
|
// these pointers MUST be correct at delete, else we probably have a dangling backpointer
|
||||||
// to this EntityItem in the corresponding data structure.
|
// to this EntityItem in the corresponding data structure.
|
||||||
assert(!_simulated);
|
assert(!_simulated);
|
||||||
|
@ -2938,3 +2930,32 @@ void EntityItem::retrieveMarketplacePublicKey() {
|
||||||
networkReply->deleteLater();
|
networkReply->deleteLater();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EntityItem::preDelete() {
|
||||||
|
// clear out any left-over actions
|
||||||
|
EntityTreeElementPointer element = _element; // use local copy of _element for logic below
|
||||||
|
EntityTreePointer entityTree = element ? element->getTree() : nullptr;
|
||||||
|
EntitySimulationPointer simulation = entityTree ? entityTree->getSimulation() : nullptr;
|
||||||
|
if (simulation) {
|
||||||
|
clearActions(simulation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityItem::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
_materials[parentMaterialName].push(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityItem::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
_materials[parentMaterialName].remove(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, graphics::MultiMaterial> EntityItem::getMaterials() {
|
||||||
|
std::unordered_map<std::string, graphics::MultiMaterial> toReturn;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||||
|
toReturn = _materials;
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
|
@ -36,6 +36,8 @@
|
||||||
#include "SimulationFlags.h"
|
#include "SimulationFlags.h"
|
||||||
#include "EntityDynamicInterface.h"
|
#include "EntityDynamicInterface.h"
|
||||||
|
|
||||||
|
#include "graphics/Material.h"
|
||||||
|
|
||||||
class EntitySimulation;
|
class EntitySimulation;
|
||||||
class EntityTreeElement;
|
class EntityTreeElement;
|
||||||
class EntityTreeElementExtraEncodeData;
|
class EntityTreeElementExtraEncodeData;
|
||||||
|
@ -49,7 +51,6 @@ typedef std::shared_ptr<EntityTreeElement> EntityTreeElementPointer;
|
||||||
using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr<EntityTreeElementExtraEncodeData>;
|
using EntityTreeElementExtraEncodeDataPointer = std::shared_ptr<EntityTreeElementExtraEncodeData>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
|
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
|
||||||
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() override { };
|
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() override { };
|
||||||
|
|
||||||
|
@ -443,10 +444,10 @@ public:
|
||||||
void scriptHasUnloaded() { _loadedScript = ""; _loadedScriptTimestamp = 0; }
|
void scriptHasUnloaded() { _loadedScript = ""; _loadedScriptTimestamp = 0; }
|
||||||
|
|
||||||
bool getClientOnly() const { return _clientOnly; }
|
bool getClientOnly() const { return _clientOnly; }
|
||||||
void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; }
|
virtual void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; }
|
||||||
// if this entity is client-only, which avatar is it associated with?
|
// if this entity is client-only, which avatar is it associated with?
|
||||||
QUuid getOwningAvatarID() const { return _owningAvatarID; }
|
QUuid getOwningAvatarID() const { return _owningAvatarID; }
|
||||||
void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; }
|
virtual void setOwningAvatarID(const QUuid& owningAvatarID) { _owningAvatarID = owningAvatarID; }
|
||||||
|
|
||||||
virtual bool wantsHandControllerPointerEvents() const { return false; }
|
virtual bool wantsHandControllerPointerEvents() const { return false; }
|
||||||
virtual bool wantsKeyboardFocus() const { return false; }
|
virtual bool wantsKeyboardFocus() const { return false; }
|
||||||
|
@ -479,6 +480,14 @@ public:
|
||||||
|
|
||||||
void setSpaceIndex(int32_t index) { assert(_spaceIndex == -1); _spaceIndex = index; }
|
void setSpaceIndex(int32_t index) { assert(_spaceIndex == -1); _spaceIndex = index; }
|
||||||
int32_t getSpaceIndex() const { return _spaceIndex; }
|
int32_t getSpaceIndex() const { return _spaceIndex; }
|
||||||
|
|
||||||
|
virtual void preDelete();
|
||||||
|
virtual void postParentFixup() {}
|
||||||
|
|
||||||
|
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||||
|
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||||
|
std::unordered_map<std::string, graphics::MultiMaterial> getMaterials();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestRenderUpdate();
|
void requestRenderUpdate();
|
||||||
|
|
||||||
|
@ -634,6 +643,11 @@ protected:
|
||||||
|
|
||||||
int32_t _spaceIndex { -1 }; // index to proxy in workload::Space
|
int32_t _spaceIndex { -1 }; // index to proxy in workload::Space
|
||||||
bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera
|
bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<std::string, graphics::MultiMaterial> _materials;
|
||||||
|
std::mutex _materialsLock;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityItem_h
|
#endif // hifi_EntityItem_h
|
||||||
|
|
|
@ -115,6 +115,17 @@ void buildStringToShapeTypeLookup() {
|
||||||
addShapeType(SHAPE_TYPE_STATIC_MESH);
|
addShapeType(SHAPE_TYPE_STATIC_MESH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QHash<QString, MaterialMappingMode> stringToMaterialMappingModeLookup;
|
||||||
|
|
||||||
|
void addMaterialMappingMode(MaterialMappingMode mode) {
|
||||||
|
stringToMaterialMappingModeLookup[MaterialMappingModeHelpers::getNameForMaterialMappingMode(mode)] = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildStringToMaterialMappingModeLookup() {
|
||||||
|
addMaterialMappingMode(UV);
|
||||||
|
addMaterialMappingMode(PROJECTED);
|
||||||
|
}
|
||||||
|
|
||||||
QString getCollisionGroupAsString(uint8_t group) {
|
QString getCollisionGroupAsString(uint8_t group) {
|
||||||
switch (group) {
|
switch (group) {
|
||||||
case USER_COLLISION_GROUP_DYNAMIC:
|
case USER_COLLISION_GROUP_DYNAMIC:
|
||||||
|
@ -259,6 +270,21 @@ void EntityItemProperties::setSkyboxModeFromString(const QString& skyboxMode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString EntityItemProperties::getMaterialMappingModeAsString() const {
|
||||||
|
return MaterialMappingModeHelpers::getNameForMaterialMappingMode(_materialMappingMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityItemProperties::setMaterialMappingModeFromString(const QString& materialMappingMode) {
|
||||||
|
if (stringToMaterialMappingModeLookup.empty()) {
|
||||||
|
buildStringToMaterialMappingModeLookup();
|
||||||
|
}
|
||||||
|
auto materialMappingModeItr = stringToMaterialMappingModeLookup.find(materialMappingMode.toLower());
|
||||||
|
if (materialMappingModeItr != stringToMaterialMappingModeLookup.end()) {
|
||||||
|
_materialMappingMode = materialMappingModeItr.value();
|
||||||
|
_materialMappingModeChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
EntityPropertyFlags changedProperties;
|
EntityPropertyFlags changedProperties;
|
||||||
|
|
||||||
|
@ -329,6 +355,13 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread);
|
CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
|
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
|
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_URL, materialURL);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_MODE, materialMappingMode);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_PARENT_MATERIAL_NAME, parentMaterialName);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_POS, materialMappingPos);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot);
|
||||||
|
|
||||||
// Certifiable Properties
|
// Certifiable Properties
|
||||||
CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName);
|
CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName);
|
||||||
|
@ -625,6 +658,17 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Materials
|
||||||
|
if (_type == EntityTypes::Material) {
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_URL, materialURL);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MATERIAL_MAPPING_MODE, materialMappingMode, getMaterialMappingModeAsString());
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_MATERIAL_NAME, parentMaterialName);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_POS, materialMappingPos);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot);
|
||||||
|
}
|
||||||
|
|
||||||
if (!skipDefaults && !strictSemantics) {
|
if (!skipDefaults && !strictSemantics) {
|
||||||
AABox aaBox = getAABox();
|
AABox aaBox = getAABox();
|
||||||
QScriptValue boundingBox = engine->newObject();
|
QScriptValue boundingBox = engine->newObject();
|
||||||
|
@ -758,6 +802,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(materialMappingMode, MaterialMappingMode);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(parentMaterialName, QString, setParentMaterialName);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingPos, glmVec2, setMaterialMappingPos);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, glmVec2, setMaterialMappingScale);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot);
|
||||||
|
|
||||||
// Certifiable Properties
|
// Certifiable Properties
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName);
|
||||||
|
@ -1112,6 +1163,14 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
||||||
ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float);
|
ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float);
|
||||||
ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
|
ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
|
||||||
|
|
||||||
|
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString);
|
||||||
|
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, materialMappingMode, MaterialMappingMode);
|
||||||
|
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, quint16);
|
||||||
|
ADD_PROPERTY_TO_MAP(PROP_PARENT_MATERIAL_NAME, ParentMaterialName, parentMaterialName, QString);
|
||||||
|
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, glmVec2);
|
||||||
|
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glmVec2);
|
||||||
|
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float);
|
||||||
|
|
||||||
// Certifiable Properties
|
// Certifiable Properties
|
||||||
ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString);
|
ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString);
|
||||||
ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString);
|
ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString);
|
||||||
|
@ -1495,6 +1554,17 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
||||||
APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape());
|
APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Materials
|
||||||
|
if (properties.getType() == EntityTypes::Material) {
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, properties.getMaterialURL());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_MODE, (uint32_t)properties.getMaterialMappingMode());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_NAME, properties.getParentMaterialName());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, properties.getMaterialMappingPos());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, properties.getMaterialMappingScale());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, properties.getMaterialMappingRot());
|
||||||
|
}
|
||||||
|
|
||||||
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
|
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
|
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
|
||||||
|
@ -1851,6 +1921,17 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE, QString, setShape);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE, QString, setShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Materials
|
||||||
|
if (properties.getType() == EntityTypes::Material) {
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_URL, QString, setMaterialURL);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, setMaterialMappingMode);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_MATERIAL_NAME, QString, setParentMaterialName);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_POS, glmVec2, setMaterialMappingPos);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_SCALE, glmVec2, setMaterialMappingScale);
|
||||||
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot);
|
||||||
|
}
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
|
||||||
|
@ -2024,6 +2105,14 @@ void EntityItemProperties::markAllChanged() {
|
||||||
//_alphaStartChanged = true;
|
//_alphaStartChanged = true;
|
||||||
//_alphaFinishChanged = true;
|
//_alphaFinishChanged = true;
|
||||||
|
|
||||||
|
_materialURLChanged = true;
|
||||||
|
_materialMappingModeChanged = true;
|
||||||
|
_priorityChanged = true;
|
||||||
|
_parentMaterialNameChanged = true;
|
||||||
|
_materialMappingPosChanged = true;
|
||||||
|
_materialMappingScaleChanged = true;
|
||||||
|
_materialMappingRotChanged = true;
|
||||||
|
|
||||||
// Certifiable Properties
|
// Certifiable Properties
|
||||||
_itemNameChanged = true;
|
_itemNameChanged = true;
|
||||||
_itemDescriptionChanged = true;
|
_itemDescriptionChanged = true;
|
||||||
|
@ -2347,6 +2436,27 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
||||||
if (radiusFinishChanged()) {
|
if (radiusFinishChanged()) {
|
||||||
out += "radiusFinish";
|
out += "radiusFinish";
|
||||||
}
|
}
|
||||||
|
if (materialURLChanged()) {
|
||||||
|
out += "materialURL";
|
||||||
|
}
|
||||||
|
if (materialMappingModeChanged()) {
|
||||||
|
out += "materialMappingMode";
|
||||||
|
}
|
||||||
|
if (priorityChanged()) {
|
||||||
|
out += "priority";
|
||||||
|
}
|
||||||
|
if (parentMaterialNameChanged()) {
|
||||||
|
out += "parentMaterialName";
|
||||||
|
}
|
||||||
|
if (materialMappingPosChanged()) {
|
||||||
|
out += "materialMappingPos";
|
||||||
|
}
|
||||||
|
if (materialMappingScaleChanged()) {
|
||||||
|
out += "materialMappingScale";
|
||||||
|
}
|
||||||
|
if (materialMappingRotChanged()) {
|
||||||
|
out += "materialMappingRot";
|
||||||
|
}
|
||||||
|
|
||||||
// Certifiable Properties
|
// Certifiable Properties
|
||||||
if (itemNameChanged()) {
|
if (itemNameChanged()) {
|
||||||
|
|
|
@ -44,6 +44,8 @@
|
||||||
#include "TextEntityItem.h"
|
#include "TextEntityItem.h"
|
||||||
#include "ZoneEntityItem.h"
|
#include "ZoneEntityItem.h"
|
||||||
|
|
||||||
|
#include "MaterialMappingMode.h"
|
||||||
|
|
||||||
const quint64 UNKNOWN_CREATED_TIME = 0;
|
const quint64 UNKNOWN_CREATED_TIME = 0;
|
||||||
|
|
||||||
using ComponentPair = std::pair<const ComponentMode, const QString>;
|
using ComponentPair = std::pair<const ComponentMode, const QString>;
|
||||||
|
@ -58,19 +60,21 @@ const std::array<ComponentPair, COMPONENT_MODE_ITEM_COUNT> COMPONENT_MODES = { {
|
||||||
/// set of entity item properties via JavaScript hashes/QScriptValues
|
/// set of entity item properties via JavaScript hashes/QScriptValues
|
||||||
/// all units for SI units (meter, second, radian, etc)
|
/// all units for SI units (meter, second, radian, etc)
|
||||||
class EntityItemProperties {
|
class EntityItemProperties {
|
||||||
friend class EntityItem; // TODO: consider removing this friend relationship and use public methods
|
// TODO: consider removing these friend relationship and use public methods
|
||||||
friend class ModelEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class EntityItem;
|
||||||
friend class BoxEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class ModelEntityItem;
|
||||||
friend class SphereEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class BoxEntityItem;
|
||||||
friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class SphereEntityItem;
|
||||||
friend class TextEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class LightEntityItem;
|
||||||
friend class ParticleEffectEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class TextEntityItem;
|
||||||
friend class ZoneEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class ParticleEffectEntityItem;
|
||||||
friend class WebEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class ZoneEntityItem;
|
||||||
friend class LineEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class WebEntityItem;
|
||||||
friend class PolyVoxEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class LineEntityItem;
|
||||||
friend class PolyLineEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class PolyVoxEntityItem;
|
||||||
friend class ShapeEntityItem; // TODO: consider removing this friend relationship and use public methods
|
friend class PolyLineEntityItem;
|
||||||
|
friend class ShapeEntityItem;
|
||||||
|
friend class MaterialEntityItem;
|
||||||
public:
|
public:
|
||||||
EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags());
|
EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags());
|
||||||
virtual ~EntityItemProperties() = default;
|
virtual ~EntityItemProperties() = default;
|
||||||
|
@ -218,6 +222,14 @@ public:
|
||||||
DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube());
|
DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube());
|
||||||
DEFINE_PROPERTY_REF(PROP_SHAPE, Shape, shape, QString, "Sphere");
|
DEFINE_PROPERTY_REF(PROP_SHAPE, Shape, shape, QString, "Sphere");
|
||||||
|
|
||||||
|
DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, "");
|
||||||
|
DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, materialMappingMode, MaterialMappingMode, UV);
|
||||||
|
DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, quint16, 0);
|
||||||
|
DEFINE_PROPERTY_REF(PROP_PARENT_MATERIAL_NAME, ParentMaterialName, parentMaterialName, QString, "0");
|
||||||
|
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, glmVec2, glm::vec2(0, 0));
|
||||||
|
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glmVec2, glm::vec2(1, 1));
|
||||||
|
DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float, 0);
|
||||||
|
|
||||||
// Certifiable Properties - related to Proof of Purchase certificates
|
// Certifiable Properties - related to Proof of Purchase certificates
|
||||||
DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME);
|
DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME);
|
||||||
DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION);
|
DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION);
|
||||||
|
|
|
@ -101,6 +101,7 @@
|
||||||
changedProperties += P; \
|
changedProperties += P; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec2& v) { return vec2toScriptValue(e, v); }
|
||||||
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3toScriptValue(e, v); }
|
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3toScriptValue(e, v); }
|
||||||
inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); }
|
inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); }
|
||||||
inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); }
|
inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); }
|
||||||
|
@ -183,6 +184,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const AACube& v) { retu
|
||||||
properties.setProperty(#P, V); \
|
properties.setProperty(#P, V); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef glm::vec2 glmVec2;
|
||||||
typedef glm::vec3 glmVec3;
|
typedef glm::vec3 glmVec3;
|
||||||
typedef glm::quat glmQuat;
|
typedef glm::quat glmQuat;
|
||||||
typedef QVector<glm::vec3> qVectorVec3;
|
typedef QVector<glm::vec3> qVectorVec3;
|
||||||
|
@ -221,6 +223,23 @@ inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool&
|
||||||
return QByteArray::fromBase64(b64.toUtf8());
|
return QByteArray::fromBase64(b64.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline glmVec2 glmVec2_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||||
|
isValid = false; /// assume it can't be converted
|
||||||
|
QScriptValue x = v.property("x");
|
||||||
|
QScriptValue y = v.property("y");
|
||||||
|
if (x.isValid() && y.isValid()) {
|
||||||
|
glm::vec4 newValue(0);
|
||||||
|
newValue.x = x.toVariant().toFloat();
|
||||||
|
newValue.y = y.toVariant().toFloat();
|
||||||
|
isValid = !glm::isnan(newValue.x) &&
|
||||||
|
!glm::isnan(newValue.y);
|
||||||
|
if (isValid) {
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glm::vec2(0);
|
||||||
|
}
|
||||||
|
|
||||||
inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||||
isValid = false; /// assume it can't be converted
|
isValid = false; /// assume it can't be converted
|
||||||
QScriptValue x = v.property("x");
|
QScriptValue x = v.property("x");
|
||||||
|
|
|
@ -227,6 +227,14 @@ enum EntityPropertyList {
|
||||||
|
|
||||||
PROP_LOCAL_DIMENSIONS, // only used to convert values to and from scripts
|
PROP_LOCAL_DIMENSIONS, // only used to convert values to and from scripts
|
||||||
|
|
||||||
|
PROP_MATERIAL_URL,
|
||||||
|
PROP_MATERIAL_MAPPING_MODE,
|
||||||
|
PROP_MATERIAL_PRIORITY,
|
||||||
|
PROP_PARENT_MATERIAL_NAME,
|
||||||
|
PROP_MATERIAL_MAPPING_POS,
|
||||||
|
PROP_MATERIAL_MAPPING_SCALE,
|
||||||
|
PROP_MATERIAL_MAPPING_ROT,
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// ATTENTION: add new properties to end of list just ABOVE this line
|
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||||
PROP_AFTER_LAST_ITEM,
|
PROP_AFTER_LAST_ITEM,
|
||||||
|
|
|
@ -1739,7 +1739,8 @@ void EntityTree::fixupNeedsParentFixups() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
entity->locationChanged(true);
|
entity->locationChanged(true);
|
||||||
} else if (getIsServer() && _avatarIDs.contains(entity->getParentID())) {
|
entity->postParentFixup();
|
||||||
|
} else if (getIsServer() || _avatarIDs.contains(entity->getParentID())) {
|
||||||
// this is a child of an avatar, which the entity server will never have
|
// this is a child of an avatar, which the entity server will never have
|
||||||
// a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves.
|
// a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves.
|
||||||
if (!_childrenOfAvatars.contains(entity->getParentID())) {
|
if (!_childrenOfAvatars.contains(entity->getParentID())) {
|
||||||
|
@ -2385,3 +2386,51 @@ QStringList EntityTree::getJointNames(const QUuid& entityID) const {
|
||||||
return entity->getJointNames();
|
return entity->getJointNames();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToEntityOperator = nullptr;
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromEntityOperator = nullptr;
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToAvatarOperator = nullptr;
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromAvatarOperator = nullptr;
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> EntityTree::_addMaterialToOverlayOperator = nullptr;
|
||||||
|
std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> EntityTree::_removeMaterialFromOverlayOperator = nullptr;
|
||||||
|
|
||||||
|
bool EntityTree::addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
if (_addMaterialToEntityOperator) {
|
||||||
|
return _addMaterialToEntityOperator(entityID, material, parentMaterialName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityTree::removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
if (_removeMaterialFromEntityOperator) {
|
||||||
|
return _removeMaterialFromEntityOperator(entityID, material, parentMaterialName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityTree::addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
if (_addMaterialToAvatarOperator) {
|
||||||
|
return _addMaterialToAvatarOperator(avatarID, material, parentMaterialName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityTree::removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
if (_removeMaterialFromAvatarOperator) {
|
||||||
|
return _removeMaterialFromAvatarOperator(avatarID, material, parentMaterialName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityTree::addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
if (_addMaterialToOverlayOperator) {
|
||||||
|
return _addMaterialToOverlayOperator(overlayID, material, parentMaterialName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityTree::removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
if (_removeMaterialFromOverlayOperator) {
|
||||||
|
return _removeMaterialFromOverlayOperator(overlayID, material, parentMaterialName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -282,6 +282,21 @@ public:
|
||||||
|
|
||||||
void queueUpdateSpaceProxy(int32_t index, const glm::vec4& sphere);
|
void queueUpdateSpaceProxy(int32_t index, const glm::vec4& sphere);
|
||||||
|
|
||||||
|
static void setAddMaterialToEntityOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToEntityOperator) { _addMaterialToEntityOperator = addMaterialToEntityOperator; }
|
||||||
|
static void setRemoveMaterialFromEntityOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromEntityOperator) { _removeMaterialFromEntityOperator = removeMaterialFromEntityOperator; }
|
||||||
|
static bool addMaterialToEntity(const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||||
|
static bool removeMaterialFromEntity(const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||||
|
|
||||||
|
static void setAddMaterialToAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToAvatarOperator) { _addMaterialToAvatarOperator = addMaterialToAvatarOperator; }
|
||||||
|
static void setRemoveMaterialFromAvatarOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromAvatarOperator) { _removeMaterialFromAvatarOperator = removeMaterialFromAvatarOperator; }
|
||||||
|
static bool addMaterialToAvatar(const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||||
|
static bool removeMaterialFromAvatar(const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||||
|
|
||||||
|
static void setAddMaterialToOverlayOperator(std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> addMaterialToOverlayOperator) { _addMaterialToOverlayOperator = addMaterialToOverlayOperator; }
|
||||||
|
static void setRemoveMaterialFromOverlayOperator(std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> removeMaterialFromOverlayOperator) { _removeMaterialFromOverlayOperator = removeMaterialFromOverlayOperator; }
|
||||||
|
static bool addMaterialToOverlay(const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||||
|
static bool removeMaterialFromOverlay(const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void deletingEntity(const EntityItemID& entityID);
|
void deletingEntity(const EntityItemID& entityID);
|
||||||
void deletingEntityPointer(EntityItem* entityID);
|
void deletingEntityPointer(EntityItem* entityID);
|
||||||
|
@ -389,6 +404,13 @@ private:
|
||||||
void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation);
|
void validatePop(const QString& certID, const EntityItemID& entityItemID, const SharedNodePointer& senderNode, bool isRetryingValidation);
|
||||||
|
|
||||||
std::shared_ptr<AvatarData> _myAvatar{ nullptr };
|
std::shared_ptr<AvatarData> _myAvatar{ nullptr };
|
||||||
|
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToEntityOperator;
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromEntityOperator;
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToAvatarOperator;
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromAvatarOperator;
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialLayer, const std::string&)> _addMaterialToOverlayOperator;
|
||||||
|
static std::function<bool(const QUuid&, graphics::MaterialPointer, const std::string&)> _removeMaterialFromOverlayOperator;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityTree_h
|
#endif // hifi_EntityTree_h
|
||||||
|
|
|
@ -896,6 +896,7 @@ EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemI
|
||||||
void EntityTreeElement::cleanupEntities() {
|
void EntityTreeElement::cleanupEntities() {
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
foreach(EntityItemPointer entity, _entityItems) {
|
foreach(EntityItemPointer entity, _entityItems) {
|
||||||
|
entity->preDelete();
|
||||||
// NOTE: only EntityTreeElement should ever be changing the value of entity->_element
|
// NOTE: only EntityTreeElement should ever be changing the value of entity->_element
|
||||||
// NOTE: We explicitly don't delete the EntityItem here because since we only
|
// NOTE: We explicitly don't delete the EntityItem here because since we only
|
||||||
// access it by smart pointers, when we remove it from the _entityItems
|
// access it by smart pointers, when we remove it from the _entityItems
|
||||||
|
@ -907,26 +908,10 @@ void EntityTreeElement::cleanupEntities() {
|
||||||
bumpChangedContent();
|
bumpChangedContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) {
|
bool EntityTreeElement::removeEntityItem(EntityItemPointer entity, bool deletion) {
|
||||||
bool foundEntity = false;
|
if (deletion) {
|
||||||
withWriteLock([&] {
|
entity->preDelete();
|
||||||
uint16_t numberOfEntities = _entityItems.size();
|
|
||||||
for (uint16_t i = 0; i < numberOfEntities; i++) {
|
|
||||||
EntityItemPointer& entity = _entityItems[i];
|
|
||||||
if (entity->getEntityItemID() == id) {
|
|
||||||
foundEntity = true;
|
|
||||||
// NOTE: only EntityTreeElement should ever be changing the value of entity->_element
|
|
||||||
entity->_element = NULL;
|
|
||||||
_entityItems.removeAt(i);
|
|
||||||
bumpChangedContent();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
return foundEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EntityTreeElement::removeEntityItem(EntityItemPointer entity) {
|
|
||||||
int numEntries = 0;
|
int numEntries = 0;
|
||||||
withWriteLock([&] {
|
withWriteLock([&] {
|
||||||
numEntries = _entityItems.removeAll(entity);
|
numEntries = _entityItems.removeAll(entity);
|
||||||
|
|
|
@ -210,8 +210,7 @@ public:
|
||||||
void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities);
|
void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities);
|
||||||
|
|
||||||
void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities
|
void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities
|
||||||
bool removeEntityWithEntityItemID(const EntityItemID& id);
|
bool removeEntityItem(EntityItemPointer entity, bool deletion = false);
|
||||||
bool removeEntityItem(EntityItemPointer entity);
|
|
||||||
|
|
||||||
bool containsEntityBounds(EntityItemPointer entity) const;
|
bool containsEntityBounds(EntityItemPointer entity) const;
|
||||||
bool bestFitEntityBounds(EntityItemPointer entity) const;
|
bool bestFitEntityBounds(EntityItemPointer entity) const;
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "PolyVoxEntityItem.h"
|
#include "PolyVoxEntityItem.h"
|
||||||
#include "PolyLineEntityItem.h"
|
#include "PolyLineEntityItem.h"
|
||||||
#include "ShapeEntityItem.h"
|
#include "ShapeEntityItem.h"
|
||||||
|
#include "MaterialEntityItem.h"
|
||||||
|
|
||||||
QMap<EntityTypes::EntityType, QString> EntityTypes::_typeToNameMap;
|
QMap<EntityTypes::EntityType, QString> EntityTypes::_typeToNameMap;
|
||||||
QMap<QString, EntityTypes::EntityType> EntityTypes::_nameToTypeMap;
|
QMap<QString, EntityTypes::EntityType> EntityTypes::_nameToTypeMap;
|
||||||
|
@ -50,6 +51,7 @@ REGISTER_ENTITY_TYPE(PolyLine)
|
||||||
REGISTER_ENTITY_TYPE(Shape)
|
REGISTER_ENTITY_TYPE(Shape)
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, ShapeEntityItem::boxFactory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Box, ShapeEntityItem::boxFactory)
|
||||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, ShapeEntityItem::sphereFactory)
|
REGISTER_ENTITY_TYPE_WITH_FACTORY(Sphere, ShapeEntityItem::sphereFactory)
|
||||||
|
REGISTER_ENTITY_TYPE(Material)
|
||||||
|
|
||||||
const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
|
const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
|
||||||
QMap<EntityType, QString>::iterator matchedTypeName = _typeToNameMap.find(entityType);
|
QMap<EntityType, QString>::iterator matchedTypeName = _typeToNameMap.find(entityType);
|
||||||
|
|
|
@ -49,7 +49,8 @@ public:
|
||||||
PolyVox,
|
PolyVox,
|
||||||
PolyLine,
|
PolyLine,
|
||||||
Shape,
|
Shape,
|
||||||
LAST = Shape
|
Material,
|
||||||
|
LAST = Material
|
||||||
} EntityType;
|
} EntityType;
|
||||||
|
|
||||||
static const QString& getEntityTypeName(EntityType entityType);
|
static const QString& getEntityTypeName(EntityType entityType);
|
||||||
|
|
339
libraries/entities/src/MaterialEntityItem.cpp
Normal file
339
libraries/entities/src/MaterialEntityItem.cpp
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 1/12/18
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "MaterialEntityItem.h"
|
||||||
|
|
||||||
|
#include "EntityItemProperties.h"
|
||||||
|
|
||||||
|
#include "QJsonDocument"
|
||||||
|
#include "QJsonArray"
|
||||||
|
|
||||||
|
EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
|
Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
|
||||||
|
entity->setProperties(properties);
|
||||||
|
// When you reload content, setProperties doesn't have any of the propertiesChanged flags set, so it won't trigger a material add
|
||||||
|
entity->removeMaterial();
|
||||||
|
entity->applyMaterial();
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// our non-pure virtual subclass for now...
|
||||||
|
MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
|
||||||
|
_type = EntityTypes::Material;
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
|
||||||
|
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingMode, getMaterialMappingMode);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentMaterialName, getParentMaterialName);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingPos, getMaterialMappingPos);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingScale, getMaterialMappingScale);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingRot, getMaterialMappingRot);
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
|
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||||
|
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingMode, setMaterialMappingMode);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentMaterialName, setParentMaterialName);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingPos, setMaterialMappingPos);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingScale, setMaterialMappingScale);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingRot, setMaterialMappingRot);
|
||||||
|
|
||||||
|
if (somethingChanged) {
|
||||||
|
bool wantDebug = false;
|
||||||
|
if (wantDebug) {
|
||||||
|
uint64_t now = usecTimestampNow();
|
||||||
|
int elapsed = now - getLastEdited();
|
||||||
|
qCDebug(entities) << "MaterialEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
|
||||||
|
"now=" << now << " getLastEdited()=" << getLastEdited();
|
||||||
|
}
|
||||||
|
setLastEdited(properties.getLastEdited());
|
||||||
|
}
|
||||||
|
return somethingChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
|
ReadBitstreamToTreeParams& args,
|
||||||
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||||
|
bool& somethingChanged) {
|
||||||
|
|
||||||
|
int bytesRead = 0;
|
||||||
|
const unsigned char* dataAt = data;
|
||||||
|
|
||||||
|
READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, setMaterialMappingMode);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, quint16, setPriority);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_NAME, QString, setParentMaterialName);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, glm::vec2, setMaterialMappingPos);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, glm::vec2, setMaterialMappingScale);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot);
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time
|
||||||
|
EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||||
|
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||||
|
requestedProperties += PROP_MATERIAL_URL;
|
||||||
|
requestedProperties += PROP_MATERIAL_MAPPING_MODE;
|
||||||
|
requestedProperties += PROP_MATERIAL_PRIORITY;
|
||||||
|
requestedProperties += PROP_PARENT_MATERIAL_NAME;
|
||||||
|
requestedProperties += PROP_MATERIAL_MAPPING_POS;
|
||||||
|
requestedProperties += PROP_MATERIAL_MAPPING_SCALE;
|
||||||
|
requestedProperties += PROP_MATERIAL_MAPPING_ROT;
|
||||||
|
return requestedProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||||
|
EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData,
|
||||||
|
EntityPropertyFlags& requestedProperties,
|
||||||
|
EntityPropertyFlags& propertyFlags,
|
||||||
|
EntityPropertyFlags& propertiesDidntFit,
|
||||||
|
int& propertyCount,
|
||||||
|
OctreeElement::AppendState& appendState) const {
|
||||||
|
|
||||||
|
bool successPropertyFits = true;
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_MODE, (uint32_t)getMaterialMappingMode());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_NAME, getParentMaterialName());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, getMaterialMappingPos());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, getMaterialMappingScale());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, getMaterialMappingRot());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::debugDump() const {
|
||||||
|
quint64 now = usecTimestampNow();
|
||||||
|
qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||||
|
qCDebug(entities) << " name:" << _name;
|
||||||
|
qCDebug(entities) << " material url:" << _materialURL;
|
||||||
|
qCDebug(entities) << " current material name:" << _currentMaterialName.c_str();
|
||||||
|
qCDebug(entities) << " material mapping mode:" << _materialMappingMode;
|
||||||
|
qCDebug(entities) << " priority:" << _priority;
|
||||||
|
qCDebug(entities) << " parent material name:" << _parentMaterialName;
|
||||||
|
qCDebug(entities) << " material mapping pos:" << _materialMappingPos;
|
||||||
|
qCDebug(entities) << " material mapping scale:" << _materialMappingRot;
|
||||||
|
qCDebug(entities) << " material mapping rot:" << _materialMappingScale;
|
||||||
|
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
|
||||||
|
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
|
||||||
|
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||||
|
qCDebug(entities) << "MATERIAL EntityItem Ptr:" << this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
||||||
|
EntityItem::setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<NetworkMaterial> MaterialEntityItem::getMaterial() const {
|
||||||
|
auto material = _parsedMaterials.networkMaterials.find(_currentMaterialName);
|
||||||
|
if (material != _parsedMaterials.networkMaterials.end()) {
|
||||||
|
return material->second;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setMaterialURL(const QString& materialURLString, bool userDataChanged) {
|
||||||
|
bool usingUserData = materialURLString.startsWith("userData");
|
||||||
|
if (_materialURL != materialURLString || (usingUserData && userDataChanged)) {
|
||||||
|
removeMaterial();
|
||||||
|
_materialURL = materialURLString;
|
||||||
|
|
||||||
|
if (materialURLString.contains("?")) {
|
||||||
|
auto split = materialURLString.split("?");
|
||||||
|
_currentMaterialName = split.last().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usingUserData) {
|
||||||
|
_parsedMaterials = NetworkMaterialResource::parseJSONMaterials(QJsonDocument::fromJson(getUserData().toUtf8()));
|
||||||
|
|
||||||
|
// Since our material changed, the current name might not be valid anymore, so we need to update
|
||||||
|
setCurrentMaterialName(_currentMaterialName);
|
||||||
|
applyMaterial();
|
||||||
|
} else {
|
||||||
|
_networkMaterial = MaterialCache::instance().getMaterial(materialURLString);
|
||||||
|
auto onMaterialRequestFinished = [&](bool success) {
|
||||||
|
if (success) {
|
||||||
|
_parsedMaterials = _networkMaterial->parsedMaterials;
|
||||||
|
|
||||||
|
setCurrentMaterialName(_currentMaterialName);
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (_networkMaterial) {
|
||||||
|
if (_networkMaterial->isLoaded()) {
|
||||||
|
onMaterialRequestFinished(!_networkMaterial->isFailed());
|
||||||
|
} else {
|
||||||
|
connect(_networkMaterial.data(), &Resource::finished, this, onMaterialRequestFinished);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setCurrentMaterialName(const std::string& currentMaterialName) {
|
||||||
|
if (_parsedMaterials.networkMaterials.find(currentMaterialName) != _parsedMaterials.networkMaterials.end()) {
|
||||||
|
_currentMaterialName = currentMaterialName;
|
||||||
|
} else if (_parsedMaterials.names.size() > 0) {
|
||||||
|
_currentMaterialName = _parsedMaterials.names[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setUserData(const QString& userData) {
|
||||||
|
if (_userData != userData) {
|
||||||
|
EntityItem::setUserData(userData);
|
||||||
|
if (_materialURL.startsWith("userData")) {
|
||||||
|
// Trigger material update when user data changes
|
||||||
|
setMaterialURL(_materialURL, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) {
|
||||||
|
if (_materialMappingPos != materialMappingPos) {
|
||||||
|
removeMaterial();
|
||||||
|
_materialMappingPos = materialMappingPos;
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) {
|
||||||
|
if (_materialMappingScale != materialMappingScale) {
|
||||||
|
removeMaterial();
|
||||||
|
_materialMappingScale = materialMappingScale;
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setMaterialMappingRot(const float& materialMappingRot) {
|
||||||
|
if (_materialMappingRot != materialMappingRot) {
|
||||||
|
removeMaterial();
|
||||||
|
_materialMappingRot = materialMappingRot;
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setPriority(quint16 priority) {
|
||||||
|
if (_priority != priority) {
|
||||||
|
removeMaterial();
|
||||||
|
_priority = priority;
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setParentMaterialName(const QString& parentMaterialName) {
|
||||||
|
if (_parentMaterialName != parentMaterialName) {
|
||||||
|
removeMaterial();
|
||||||
|
_parentMaterialName = parentMaterialName;
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setParentID(const QUuid& parentID) {
|
||||||
|
if (getParentID() != parentID) {
|
||||||
|
removeMaterial();
|
||||||
|
EntityItem::setParentID(parentID);
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setClientOnly(bool clientOnly) {
|
||||||
|
if (getClientOnly() != clientOnly) {
|
||||||
|
removeMaterial();
|
||||||
|
EntityItem::setClientOnly(clientOnly);
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::setOwningAvatarID(const QUuid& owningAvatarID) {
|
||||||
|
if (getOwningAvatarID() != owningAvatarID) {
|
||||||
|
removeMaterial();
|
||||||
|
EntityItem::setOwningAvatarID(owningAvatarID);
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::removeMaterial() {
|
||||||
|
graphics::MaterialPointer material = getMaterial();
|
||||||
|
QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID();
|
||||||
|
if (!material || parentID.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our parent could be an entity, an avatar, or an overlay
|
||||||
|
if (EntityTree::removeMaterialFromEntity(parentID, material, getParentMaterialName().toStdString())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityTree::removeMaterialFromAvatar(parentID, material, getParentMaterialName().toStdString())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityTree::removeMaterialFromOverlay(parentID, material, getParentMaterialName().toStdString())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if a remove fails, our parent is gone, so we don't need to retry
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::applyMaterial() {
|
||||||
|
_retryApply = false;
|
||||||
|
graphics::MaterialPointer material = getMaterial();
|
||||||
|
QUuid parentID = getClientOnly() ? getOwningAvatarID() : getParentID();
|
||||||
|
if (!material || parentID.isNull()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Transform textureTransform;
|
||||||
|
textureTransform.setTranslation(glm::vec3(_materialMappingPos, 0));
|
||||||
|
textureTransform.setRotation(glm::vec3(0, 0, glm::radians(_materialMappingRot)));
|
||||||
|
textureTransform.setScale(glm::vec3(_materialMappingScale, 1));
|
||||||
|
material->setTextureTransforms(textureTransform);
|
||||||
|
|
||||||
|
graphics::MaterialLayer materialLayer = graphics::MaterialLayer(material, getPriority());
|
||||||
|
|
||||||
|
// Our parent could be an entity, an avatar, or an overlay
|
||||||
|
if (EntityTree::addMaterialToEntity(parentID, materialLayer, getParentMaterialName().toStdString())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityTree::addMaterialToAvatar(parentID, materialLayer, getParentMaterialName().toStdString())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityTree::addMaterialToOverlay(parentID, materialLayer, getParentMaterialName().toStdString())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we've reached this point, we couldn't find our parent, so we need to try again later
|
||||||
|
_retryApply = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::postParentFixup() {
|
||||||
|
removeMaterial();
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::preDelete() {
|
||||||
|
EntityItem::preDelete();
|
||||||
|
removeMaterial();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialEntityItem::update(const quint64& now) {
|
||||||
|
if (_retryApply) {
|
||||||
|
applyMaterial();
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityItem::update(now);
|
||||||
|
}
|
129
libraries/entities/src/MaterialEntityItem.h
Normal file
129
libraries/entities/src/MaterialEntityItem.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 1/12/18
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_MaterialEntityItem_h
|
||||||
|
#define hifi_MaterialEntityItem_h
|
||||||
|
|
||||||
|
#include "EntityItem.h"
|
||||||
|
|
||||||
|
#include "MaterialMappingMode.h"
|
||||||
|
#include <model-networking/ModelCache.h>
|
||||||
|
#include <model-networking/MaterialCache.h>
|
||||||
|
|
||||||
|
class MaterialEntityItem : public EntityItem {
|
||||||
|
using Pointer = std::shared_ptr<MaterialEntityItem>;
|
||||||
|
public:
|
||||||
|
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||||
|
|
||||||
|
MaterialEntityItem(const EntityItemID& entityItemID);
|
||||||
|
|
||||||
|
ALLOW_INSTANTIATION // This class can be instantiated
|
||||||
|
|
||||||
|
void update(const quint64& now) override;
|
||||||
|
bool needsToCallUpdate() const override { return true; }
|
||||||
|
|
||||||
|
// methods for getting/setting all properties of an entity
|
||||||
|
virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override;
|
||||||
|
virtual bool setProperties(const EntityItemProperties& properties) override;
|
||||||
|
|
||||||
|
// TODO: eventually only include properties changed since the params.nodeData->getLastTimeBagEmpty() time
|
||||||
|
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
|
||||||
|
|
||||||
|
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||||
|
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
|
||||||
|
EntityPropertyFlags& requestedProperties,
|
||||||
|
EntityPropertyFlags& propertyFlags,
|
||||||
|
EntityPropertyFlags& propertiesDidntFit,
|
||||||
|
int& propertyCount,
|
||||||
|
OctreeElement::AppendState& appendState) const override;
|
||||||
|
|
||||||
|
|
||||||
|
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||||
|
ReadBitstreamToTreeParams& args,
|
||||||
|
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||||
|
bool& somethingChanged) override;
|
||||||
|
|
||||||
|
void debugDump() const override;
|
||||||
|
|
||||||
|
virtual void setUnscaledDimensions(const glm::vec3& value) override;
|
||||||
|
|
||||||
|
QString getMaterialURL() const { return _materialURL; }
|
||||||
|
void setMaterialURL(const QString& materialURLString, bool userDataChanged = false);
|
||||||
|
|
||||||
|
void setCurrentMaterialName(const std::string& currentMaterialName);
|
||||||
|
|
||||||
|
MaterialMappingMode getMaterialMappingMode() const { return _materialMappingMode; }
|
||||||
|
void setMaterialMappingMode(MaterialMappingMode mode) { _materialMappingMode = mode; }
|
||||||
|
|
||||||
|
quint16 getPriority() const { return _priority; }
|
||||||
|
void setPriority(quint16 priority);
|
||||||
|
|
||||||
|
QString getParentMaterialName() const { return _parentMaterialName; }
|
||||||
|
void setParentMaterialName(const QString& parentMaterialName);
|
||||||
|
|
||||||
|
glm::vec2 getMaterialMappingPos() const { return _materialMappingPos; }
|
||||||
|
void setMaterialMappingPos(const glm::vec2& materialMappingPos);
|
||||||
|
glm::vec2 getMaterialMappingScale() const { return _materialMappingScale; }
|
||||||
|
void setMaterialMappingScale(const glm::vec2& materialMappingScale);
|
||||||
|
float getMaterialMappingRot() const { return _materialMappingRot; }
|
||||||
|
void setMaterialMappingRot(const float& materialMappingRot);
|
||||||
|
|
||||||
|
std::shared_ptr<NetworkMaterial> getMaterial() const;
|
||||||
|
|
||||||
|
void setUserData(const QString& userData) override;
|
||||||
|
void setParentID(const QUuid& parentID) override;
|
||||||
|
void setClientOnly(bool clientOnly) override;
|
||||||
|
void setOwningAvatarID(const QUuid& owningAvatarID) override;
|
||||||
|
|
||||||
|
void applyMaterial();
|
||||||
|
void removeMaterial();
|
||||||
|
|
||||||
|
void postParentFixup() override;
|
||||||
|
void preDelete() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// URL for this material. Currently, only JSON format is supported. Set to "userData" to use the user data to live edit a material.
|
||||||
|
// The following fields are supported in the JSON:
|
||||||
|
// materialVersion: a uint for the version of this network material (currently, only 1 is supported)
|
||||||
|
// materials, which is either an object or an array of objects, each with the following properties:
|
||||||
|
// strings:
|
||||||
|
// name (NOT YET USED), model (NOT YET USED, should use "hifi_pbr")
|
||||||
|
// floats:
|
||||||
|
// opacity, roughness, metallic, scattering
|
||||||
|
// bool:
|
||||||
|
// unlit
|
||||||
|
// colors (arrays of 3 floats 0-1. Optional fourth value in array can be a boolean isSRGB):
|
||||||
|
// emissive, albedo
|
||||||
|
// urls to textures:
|
||||||
|
// 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
|
||||||
|
MaterialMappingMode _materialMappingMode { UV };
|
||||||
|
// 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 };
|
||||||
|
// An identifier for choosing a submesh or submeshes within a parent. If in the format "mat::<string>", all submeshes with material name "<string>" will be replaced. Otherwise,
|
||||||
|
// parentMaterialName will be parsed as an unsigned int (strings not starting with "mat::" will parse to 0), representing the mesh index to modify.
|
||||||
|
QString _parentMaterialName { "0" };
|
||||||
|
// Offset position in UV-space of top left of material, (0, 0) to (1, 1)
|
||||||
|
glm::vec2 _materialMappingPos { 0, 0 };
|
||||||
|
// How much to scale this material within its parent's UV-space
|
||||||
|
glm::vec2 _materialMappingScale { 1, 1 };
|
||||||
|
// How much to rotate this material within its parent's UV-space (degrees)
|
||||||
|
float _materialMappingRot { 0 };
|
||||||
|
|
||||||
|
NetworkMaterialResourcePointer _networkMaterial;
|
||||||
|
NetworkMaterialResource::ParsedMaterials _parsedMaterials;
|
||||||
|
std::string _currentMaterialName;
|
||||||
|
|
||||||
|
bool _retryApply { false };
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_MaterialEntityItem_h
|
|
@ -85,6 +85,7 @@ EntityItemPointer ShapeEntityItem::sphereFactory(const EntityItemID& entityID, c
|
||||||
ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
|
ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) {
|
||||||
_type = EntityTypes::Shape;
|
_type = EntityTypes::Shape;
|
||||||
_volumeMultiplier *= PI / 6.0f;
|
_volumeMultiplier *= PI / 6.0f;
|
||||||
|
_material = std::make_shared<graphics::Material>();
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
|
EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
|
||||||
|
@ -184,6 +185,7 @@ void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
||||||
|
|
||||||
void ShapeEntityItem::setColor(const rgbColor& value) {
|
void ShapeEntityItem::setColor(const rgbColor& value) {
|
||||||
memcpy(_color, value, sizeof(rgbColor));
|
memcpy(_color, value, sizeof(rgbColor));
|
||||||
|
_material->setAlbedo(glm::vec3(_color[0], _color[1], _color[2]) / 255.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
xColor ShapeEntityItem::getXColor() const {
|
xColor ShapeEntityItem::getXColor() const {
|
||||||
|
@ -204,6 +206,11 @@ void ShapeEntityItem::setColor(const QColor& value) {
|
||||||
setAlpha(value.alpha());
|
setAlpha(value.alpha());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShapeEntityItem::setAlpha(float alpha) {
|
||||||
|
_alpha = alpha;
|
||||||
|
_material->setOpacity(alpha);
|
||||||
|
}
|
||||||
|
|
||||||
void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) {
|
||||||
const float MAX_FLAT_DIMENSION = 0.0001f;
|
const float MAX_FLAT_DIMENSION = 0.0001f;
|
||||||
if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
|
if ((_shape == entity::Shape::Circle || _shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) {
|
||||||
|
|
|
@ -75,7 +75,7 @@ public:
|
||||||
void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); }
|
void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); }
|
||||||
|
|
||||||
float getAlpha() const { return _alpha; };
|
float getAlpha() const { return _alpha; };
|
||||||
void setAlpha(float alpha) { _alpha = alpha; }
|
void setAlpha(float alpha);
|
||||||
|
|
||||||
const rgbColor& getColor() const { return _color; }
|
const rgbColor& getColor() const { return _color; }
|
||||||
void setColor(const rgbColor& value);
|
void setColor(const rgbColor& value);
|
||||||
|
@ -101,6 +101,8 @@ public:
|
||||||
virtual void computeShapeInfo(ShapeInfo& info) override;
|
virtual void computeShapeInfo(ShapeInfo& info) override;
|
||||||
virtual ShapeType getShapeType() const override;
|
virtual ShapeType getShapeType() const override;
|
||||||
|
|
||||||
|
std::shared_ptr<graphics::Material> getMaterial() { return _material; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
float _alpha { 1 };
|
float _alpha { 1 };
|
||||||
|
@ -111,6 +113,8 @@ protected:
|
||||||
//! prior functionality where new or unsupported shapes are treated as
|
//! prior functionality where new or unsupported shapes are treated as
|
||||||
//! ellipsoids.
|
//! ellipsoids.
|
||||||
ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID };
|
ShapeType _collisionShapeType{ ShapeType::SHAPE_TYPE_ELLIPSOID };
|
||||||
|
|
||||||
|
std::shared_ptr<graphics::Material> _material;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ShapeEntityItem_h
|
#endif // hifi_ShapeEntityItem_h
|
||||||
|
|
|
@ -1481,6 +1481,11 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
||||||
}
|
}
|
||||||
while (!remainingModels.isEmpty()) {
|
while (!remainingModels.isEmpty()) {
|
||||||
QString first = *remainingModels.constBegin();
|
QString first = *remainingModels.constBegin();
|
||||||
|
foreach (const QString& id, remainingModels) {
|
||||||
|
if (id < first) {
|
||||||
|
first = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
QString topID = getTopModelID(_connectionParentMap, models, first, url);
|
QString topID = getTopModelID(_connectionParentMap, models, first, url);
|
||||||
appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, models, remainingModels, modelIDs, true);
|
appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, models, remainingModels, modelIDs, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include "TextureMap.h"
|
#include "TextureMap.h"
|
||||||
|
|
||||||
|
#include <Transform.h>
|
||||||
|
|
||||||
using namespace graphics;
|
using namespace graphics;
|
||||||
using namespace gpu;
|
using namespace gpu;
|
||||||
|
|
||||||
|
@ -30,6 +32,7 @@ Material::Material() :
|
||||||
}
|
}
|
||||||
|
|
||||||
Material::Material(const Material& material) :
|
Material::Material(const Material& material) :
|
||||||
|
_name(material._name),
|
||||||
_key(material._key),
|
_key(material._key),
|
||||||
_textureMaps(material._textureMaps)
|
_textureMaps(material._textureMaps)
|
||||||
{
|
{
|
||||||
|
@ -46,6 +49,8 @@ Material::Material(const Material& material) :
|
||||||
Material& Material::operator= (const Material& material) {
|
Material& Material::operator= (const Material& material) {
|
||||||
QMutexLocker locker(&_textureMapsMutex);
|
QMutexLocker locker(&_textureMapsMutex);
|
||||||
|
|
||||||
|
_name = material._name;
|
||||||
|
|
||||||
_key = (material._key);
|
_key = (material._key);
|
||||||
_textureMaps = (material._textureMaps);
|
_textureMaps = (material._textureMaps);
|
||||||
_hasCalculatedTextureInfo = false;
|
_hasCalculatedTextureInfo = false;
|
||||||
|
@ -222,3 +227,14 @@ bool Material::calculateMaterialInfo() const {
|
||||||
}
|
}
|
||||||
return _hasCalculatedTextureInfo;
|
return _hasCalculatedTextureInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Material::setTextureTransforms(const Transform& transform) {
|
||||||
|
for (auto &textureMapItem : _textureMaps) {
|
||||||
|
if (textureMapItem.second) {
|
||||||
|
textureMapItem.second->setTextureTransform(transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < NUM_TEXCOORD_TRANSFORMS; i++) {
|
||||||
|
_texMapArrayBuffer.edit<TexMapArraySchema>()._texcoordTransforms[i] = transform.getMatrix();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,11 +15,14 @@
|
||||||
|
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
#include <ColorUtils.h>
|
#include <ColorUtils.h>
|
||||||
|
|
||||||
#include <gpu/Resource.h>
|
#include <gpu/Resource.h>
|
||||||
|
|
||||||
|
class Transform;
|
||||||
|
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
|
|
||||||
class TextureMap;
|
class TextureMap;
|
||||||
|
@ -351,6 +354,15 @@ public:
|
||||||
size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; }
|
size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; }
|
||||||
bool hasTextureInfo() const { return _hasCalculatedTextureInfo; }
|
bool hasTextureInfo() const { return _hasCalculatedTextureInfo; }
|
||||||
|
|
||||||
|
void setTextureTransforms(const Transform& transform);
|
||||||
|
|
||||||
|
const std::string& getName() { return _name; }
|
||||||
|
|
||||||
|
void setModel(const std::string& model) { _model = model; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string _name { "" };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable MaterialKey _key;
|
mutable MaterialKey _key;
|
||||||
mutable UniformBufferView _schemaBuffer;
|
mutable UniformBufferView _schemaBuffer;
|
||||||
|
@ -364,10 +376,46 @@ private:
|
||||||
mutable bool _hasCalculatedTextureInfo { false };
|
mutable bool _hasCalculatedTextureInfo { false };
|
||||||
bool calculateMaterialInfo() const;
|
bool calculateMaterialInfo() const;
|
||||||
|
|
||||||
|
std::string _model { "hifi_pbr" };
|
||||||
|
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr< Material > MaterialPointer;
|
typedef std::shared_ptr< Material > MaterialPointer;
|
||||||
|
|
||||||
|
class MaterialLayer {
|
||||||
|
public:
|
||||||
|
MaterialLayer(MaterialPointer material, quint16 priority) : material(material), priority(priority) {}
|
||||||
|
|
||||||
|
MaterialPointer material { nullptr };
|
||||||
|
quint16 priority { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
class MaterialLayerCompare {
|
||||||
|
public:
|
||||||
|
bool operator() (MaterialLayer left, MaterialLayer right) {
|
||||||
|
return left.priority < right.priority;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MultiMaterial : public std::priority_queue<MaterialLayer, std::vector<MaterialLayer>, MaterialLayerCompare> {
|
||||||
|
public:
|
||||||
|
bool remove(const MaterialPointer& value) {
|
||||||
|
auto it = c.begin();
|
||||||
|
while (it != c.end()) {
|
||||||
|
if (it->material == value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
if (it != c.end()) {
|
||||||
|
c.erase(it);
|
||||||
|
std::make_heap(c.begin(), c.end(), comp);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,208 @@
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 2/9/2018
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#include "MaterialCache.h"
|
||||||
|
|
||||||
|
#include "QJsonObject"
|
||||||
|
#include "QJsonDocument"
|
||||||
|
#include "QJsonArray"
|
||||||
|
|
||||||
|
NetworkMaterialResource::NetworkMaterialResource(const QUrl& url) :
|
||||||
|
Resource(url) {}
|
||||||
|
|
||||||
|
void NetworkMaterialResource::downloadFinished(const QByteArray& data) {
|
||||||
|
parsedMaterials.reset();
|
||||||
|
|
||||||
|
if (_url.toString().contains(".json")) {
|
||||||
|
parsedMaterials = parseJSONMaterials(QJsonDocument::fromJson(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: parse other material types
|
||||||
|
|
||||||
|
finishedLoading(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetworkMaterialResource::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) {
|
||||||
|
if (array.isArray()) {
|
||||||
|
QJsonArray colorArray = array.toArray();
|
||||||
|
if (colorArray.size() >= 3 && colorArray[0].isDouble() && colorArray[1].isDouble() && colorArray[2].isDouble()) {
|
||||||
|
isSRGB = true;
|
||||||
|
if (colorArray.size() >= 4) {
|
||||||
|
if (colorArray[3].isBool()) {
|
||||||
|
isSRGB = colorArray[3].toBool();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkMaterialResource::ParsedMaterials NetworkMaterialResource::parseJSONMaterials(const QJsonDocument& materialJSON) {
|
||||||
|
ParsedMaterials toReturn;
|
||||||
|
if (!materialJSON.isNull() && materialJSON.isObject()) {
|
||||||
|
QJsonObject materialJSONObject = materialJSON.object();
|
||||||
|
for (auto& key : materialJSONObject.keys()) {
|
||||||
|
if (key == "materialVersion") {
|
||||||
|
auto value = materialJSONObject.value(key);
|
||||||
|
if (value.isDouble()) {
|
||||||
|
toReturn.version = (uint)value.toInt();
|
||||||
|
}
|
||||||
|
} else if (key == "materials") {
|
||||||
|
auto materialsValue = materialJSONObject.value(key);
|
||||||
|
if (materialsValue.isArray()) {
|
||||||
|
QJsonArray materials = materialsValue.toArray();
|
||||||
|
for (auto material : materials) {
|
||||||
|
if (!material.isNull() && material.isObject()) {
|
||||||
|
auto parsedMaterial = parseJSONMaterial(material.toObject());
|
||||||
|
toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second;
|
||||||
|
toReturn.names.push_back(parsedMaterial.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (materialsValue.isObject()) {
|
||||||
|
auto parsedMaterial = parseJSONMaterial(materialsValue.toObject());
|
||||||
|
toReturn.networkMaterials[parsedMaterial.first] = parsedMaterial.second;
|
||||||
|
toReturn.names.push_back(parsedMaterial.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, std::shared_ptr<NetworkMaterial>> NetworkMaterialResource::parseJSONMaterial(const QJsonObject& materialJSON) {
|
||||||
|
std::string name = "";
|
||||||
|
std::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>();
|
||||||
|
for (auto& key : materialJSON.keys()) {
|
||||||
|
if (key == "name") {
|
||||||
|
auto nameJSON = materialJSON.value(key);
|
||||||
|
if (nameJSON.isString()) {
|
||||||
|
name = nameJSON.toString().toStdString();
|
||||||
|
}
|
||||||
|
} else if (key == "model") {
|
||||||
|
auto modelJSON = materialJSON.value(key);
|
||||||
|
if (modelJSON.isString()) {
|
||||||
|
material->setModel(modelJSON.toString().toStdString());
|
||||||
|
}
|
||||||
|
} else if (key == "emissive") {
|
||||||
|
glm::vec3 color;
|
||||||
|
bool isSRGB;
|
||||||
|
bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB);
|
||||||
|
if (valid) {
|
||||||
|
material->setEmissive(color, isSRGB);
|
||||||
|
}
|
||||||
|
} else if (key == "opacity") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isDouble()) {
|
||||||
|
material->setOpacity(value.toDouble());
|
||||||
|
}
|
||||||
|
} else if (key == "unlit") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isBool()) {
|
||||||
|
material->setUnlit(value.toBool());
|
||||||
|
}
|
||||||
|
} else if (key == "albedo") {
|
||||||
|
glm::vec3 color;
|
||||||
|
bool isSRGB;
|
||||||
|
bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB);
|
||||||
|
if (valid) {
|
||||||
|
material->setAlbedo(color, isSRGB);
|
||||||
|
}
|
||||||
|
} else if (key == "roughness") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isDouble()) {
|
||||||
|
material->setRoughness(value.toDouble());
|
||||||
|
}
|
||||||
|
} else if (key == "metallic") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isDouble()) {
|
||||||
|
material->setMetallic(value.toDouble());
|
||||||
|
}
|
||||||
|
} else if (key == "scattering") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isDouble()) {
|
||||||
|
material->setScattering(value.toDouble());
|
||||||
|
}
|
||||||
|
} else if (key == "emissiveMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setEmissiveMap(value.toString());
|
||||||
|
}
|
||||||
|
} else if (key == "albedoMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
bool useAlphaChannel = false;
|
||||||
|
auto opacityMap = materialJSON.find("opacityMap");
|
||||||
|
if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) {
|
||||||
|
useAlphaChannel = true;
|
||||||
|
}
|
||||||
|
material->setAlbedoMap(value.toString(), useAlphaChannel);
|
||||||
|
}
|
||||||
|
} else if (key == "roughnessMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setRoughnessMap(value.toString(), false);
|
||||||
|
}
|
||||||
|
} else if (key == "glossMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setRoughnessMap(value.toString(), true);
|
||||||
|
}
|
||||||
|
} else if (key == "metallicMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setMetallicMap(value.toString(), false);
|
||||||
|
}
|
||||||
|
} else if (key == "specularMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setMetallicMap(value.toString(), true);
|
||||||
|
}
|
||||||
|
} else if (key == "normalMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setNormalMap(value.toString(), false);
|
||||||
|
}
|
||||||
|
} else if (key == "bumpMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setNormalMap(value.toString(), true);
|
||||||
|
}
|
||||||
|
} else if (key == "occlusionMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setOcclusionMap(value.toString());
|
||||||
|
}
|
||||||
|
} else if (key == "scatteringMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setScatteringMap(value.toString());
|
||||||
|
}
|
||||||
|
} else if (key == "lightMap") {
|
||||||
|
auto value = materialJSON.value(key);
|
||||||
|
if (value.isString()) {
|
||||||
|
material->setLightmapMap(value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::pair<std::string, std::shared_ptr<NetworkMaterial>>(name, material);
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialCache& MaterialCache::instance() {
|
||||||
|
static MaterialCache _instance;
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkMaterialResourcePointer MaterialCache::getMaterial(const QUrl& url) {
|
||||||
|
return ResourceCache::getResource(url, QUrl(), nullptr).staticCast<NetworkMaterialResource>();
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<Resource> MaterialCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) {
|
||||||
|
return QSharedPointer<Resource>(new NetworkMaterialResource(url), &Resource::deleter);
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 2/9/2018
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#ifndef hifi_MaterialCache_h
|
||||||
|
#define hifi_MaterialCache_h
|
||||||
|
|
||||||
|
#include <ResourceCache.h>
|
||||||
|
|
||||||
|
#include "glm/glm.hpp"
|
||||||
|
|
||||||
|
#include "ModelCache.h"
|
||||||
|
|
||||||
|
class NetworkMaterialResource : public Resource {
|
||||||
|
public:
|
||||||
|
NetworkMaterialResource(const QUrl& url);
|
||||||
|
|
||||||
|
QString getType() const override { return "NetworkMaterial"; }
|
||||||
|
|
||||||
|
virtual void downloadFinished(const QByteArray& data) override;
|
||||||
|
|
||||||
|
typedef struct ParsedMaterials {
|
||||||
|
uint version { 1 };
|
||||||
|
std::vector<std::string> names;
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<NetworkMaterial>> networkMaterials;
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
version = 1;
|
||||||
|
names.clear();
|
||||||
|
networkMaterials.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} ParsedMaterials;
|
||||||
|
|
||||||
|
ParsedMaterials parsedMaterials;
|
||||||
|
|
||||||
|
static ParsedMaterials parseJSONMaterials(const QJsonDocument& materialJSON);
|
||||||
|
static std::pair<std::string, std::shared_ptr<NetworkMaterial>> parseJSONMaterial(const QJsonObject& materialJSON);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB);
|
||||||
|
};
|
||||||
|
|
||||||
|
using NetworkMaterialResourcePointer = QSharedPointer<NetworkMaterialResource>;
|
||||||
|
|
||||||
|
class MaterialCache : public ResourceCache {
|
||||||
|
public:
|
||||||
|
static MaterialCache& instance();
|
||||||
|
|
||||||
|
NetworkMaterialResourcePointer getMaterial(const QUrl& url);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -425,7 +425,7 @@ bool Geometry::areTexturesLoaded() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::shared_ptr<const NetworkMaterial> Geometry::getShapeMaterial(int partID) const {
|
const std::shared_ptr<NetworkMaterial> Geometry::getShapeMaterial(int partID) const {
|
||||||
if ((partID >= 0) && (partID < (int)_meshParts->size())) {
|
if ((partID >= 0) && (partID < (int)_meshParts->size())) {
|
||||||
int materialID = _meshParts->at(partID)->materialID;
|
int materialID = _meshParts->at(partID)->materialID;
|
||||||
if ((materialID >= 0) && (materialID < (int)_materials.size())) {
|
if ((materialID >= 0) && (materialID < (int)_materials.size())) {
|
||||||
|
@ -491,6 +491,15 @@ void GeometryResourceWatcher::resourceRefreshed() {
|
||||||
// _instance.reset();
|
// _instance.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) :
|
||||||
|
Material(m),
|
||||||
|
_textures(m._textures),
|
||||||
|
_albedoTransform(m._albedoTransform),
|
||||||
|
_lightmapTransform(m._lightmapTransform),
|
||||||
|
_lightmapParams(m._lightmapParams),
|
||||||
|
_isOriginal(m._isOriginal)
|
||||||
|
{}
|
||||||
|
|
||||||
const QString NetworkMaterial::NO_TEXTURE = QString();
|
const QString NetworkMaterial::NO_TEXTURE = QString();
|
||||||
|
|
||||||
const QString& NetworkMaterial::getTextureName(MapChannel channel) {
|
const QString& NetworkMaterial::getTextureName(MapChannel channel) {
|
||||||
|
@ -532,19 +541,85 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel) {
|
graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel) {
|
||||||
const auto texture = DependencyManager::get<TextureCache>()->getTexture(url, type);
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
|
if (textureCache) {
|
||||||
|
auto texture = textureCache->getTexture(url, type);
|
||||||
_textures[channel].texture = texture;
|
_textures[channel].texture = texture;
|
||||||
|
|
||||||
auto map = std::make_shared<graphics::TextureMap>();
|
auto map = std::make_shared<graphics::TextureMap>();
|
||||||
|
if (texture) {
|
||||||
map->setTextureSource(texture->_textureSource);
|
map->setTextureSource(texture->_textureSource);
|
||||||
|
}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkMaterial::setAlbedoMap(const QString& url, bool useAlphaChannel) {
|
||||||
|
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||||
|
if (map) {
|
||||||
|
map->setUseAlphaChannel(useAlphaChannel);
|
||||||
|
setTextureMap(MapChannel::ALBEDO_MAP, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkMaterial::setNormalMap(const QString& url, bool isBumpmap) {
|
||||||
|
auto map = fetchTextureMap(QUrl(url), isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP);
|
||||||
|
if (map) {
|
||||||
|
setTextureMap(MapChannel::NORMAL_MAP, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkMaterial::setRoughnessMap(const QString& url, bool isGloss) {
|
||||||
|
auto map = fetchTextureMap(QUrl(url), isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP);
|
||||||
|
if (map) {
|
||||||
|
setTextureMap(MapChannel::ROUGHNESS_MAP, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkMaterial::setMetallicMap(const QString& url, bool isSpecular) {
|
||||||
|
auto map = fetchTextureMap(QUrl(url), isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP);
|
||||||
|
if (map) {
|
||||||
|
setTextureMap(MapChannel::METALLIC_MAP, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkMaterial::setOcclusionMap(const QString& url) {
|
||||||
|
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
|
||||||
|
if (map) {
|
||||||
|
setTextureMap(MapChannel::OCCLUSION_MAP, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkMaterial::setEmissiveMap(const QString& url) {
|
||||||
|
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP);
|
||||||
|
if (map) {
|
||||||
|
setTextureMap(MapChannel::EMISSIVE_MAP, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkMaterial::setScatteringMap(const QString& url) {
|
||||||
|
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP);
|
||||||
|
if (map) {
|
||||||
|
setTextureMap(MapChannel::SCATTERING_MAP, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkMaterial::setLightmapMap(const QString& url) {
|
||||||
|
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP);
|
||||||
|
if (map) {
|
||||||
|
//map->setTextureTransform(_lightmapTransform);
|
||||||
|
//map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y);
|
||||||
|
setTextureMap(MapChannel::LIGHTMAP_MAP, map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) :
|
NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) :
|
||||||
graphics::Material(*material._material)
|
graphics::Material(*material._material),
|
||||||
|
_textures(MapChannel::NUM_MAP_CHANNELS)
|
||||||
{
|
{
|
||||||
_textures = Textures(MapChannel::NUM_MAP_CHANNELS);
|
_name = material.name.toStdString();
|
||||||
if (!material.albedoTexture.filename.isEmpty()) {
|
if (!material.albedoTexture.filename.isEmpty()) {
|
||||||
auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
|
||||||
_albedoTransform = material.albedoTexture.transform;
|
_albedoTransform = material.albedoTexture.transform;
|
||||||
|
@ -653,6 +728,7 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) {
|
||||||
|
|
||||||
if (!occlusionName.isEmpty()) {
|
if (!occlusionName.isEmpty()) {
|
||||||
auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl();
|
auto url = textureMap.contains(occlusionName) ? textureMap[occlusionName].toUrl() : QUrl();
|
||||||
|
// FIXME: we need to handle the occlusion map transform here
|
||||||
auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
|
auto map = fetchTextureMap(url, image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
|
||||||
setTextureMap(MapChannel::OCCLUSION_MAP, map);
|
setTextureMap(MapChannel::OCCLUSION_MAP, map);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
|
|
||||||
const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; }
|
const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; }
|
||||||
const GeometryMeshes& getMeshes() const { return *_meshes; }
|
const GeometryMeshes& getMeshes() const { return *_meshes; }
|
||||||
const std::shared_ptr<const NetworkMaterial> getShapeMaterial(int shapeID) const;
|
const std::shared_ptr<NetworkMaterial> getShapeMaterial(int shapeID) const;
|
||||||
|
|
||||||
const QVariantMap getTextures() const;
|
const QVariantMap getTextures() const;
|
||||||
void setTextures(const QVariantMap& textureMap);
|
void setTextures(const QVariantMap& textureMap);
|
||||||
|
@ -131,7 +131,6 @@ private:
|
||||||
Geometry::Pointer& _geometryRef;
|
Geometry::Pointer& _geometryRef;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Stores cached model geometries.
|
/// Stores cached model geometries.
|
||||||
class ModelCache : public ResourceCache, public Dependency {
|
class ModelCache : public ResourceCache, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -161,7 +160,18 @@ class NetworkMaterial : public graphics::Material {
|
||||||
public:
|
public:
|
||||||
using MapChannel = graphics::Material::MapChannel;
|
using MapChannel = graphics::Material::MapChannel;
|
||||||
|
|
||||||
|
NetworkMaterial() : _textures(MapChannel::NUM_MAP_CHANNELS) {}
|
||||||
NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl);
|
NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl);
|
||||||
|
NetworkMaterial(const NetworkMaterial& material);
|
||||||
|
|
||||||
|
void setAlbedoMap(const QString& url, bool useAlphaChannel);
|
||||||
|
void setNormalMap(const QString& url, bool isBumpmap);
|
||||||
|
void setRoughnessMap(const QString& url, bool isGloss);
|
||||||
|
void setMetallicMap(const QString& url, bool isSpecular);
|
||||||
|
void setOcclusionMap(const QString& url);
|
||||||
|
void setEmissiveMap(const QString& url);
|
||||||
|
void setScatteringMap(const QString& url);
|
||||||
|
void setLightmapMap(const QString& url);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class Geometry;
|
friend class Geometry;
|
||||||
|
|
|
@ -283,6 +283,8 @@ QSharedPointer<Resource> TextureCache::createResource(const QUrl& url, const QSh
|
||||||
return QSharedPointer<Resource>(texture, &Resource::deleter);
|
return QSharedPointer<Resource>(texture, &Resource::deleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int networkTexturePointerMetaTypeId = qRegisterMetaType<QWeakPointer<NetworkTexture>>();
|
||||||
|
|
||||||
NetworkTexture::NetworkTexture(const QUrl& url) :
|
NetworkTexture::NetworkTexture(const QUrl& url) :
|
||||||
Resource(url),
|
Resource(url),
|
||||||
_type(),
|
_type(),
|
||||||
|
|
|
@ -163,7 +163,6 @@ public:
|
||||||
NetworkTexturePointer getTexture(const QUrl& url, image::TextureUsage::Type type = image::TextureUsage::DEFAULT_TEXTURE,
|
NetworkTexturePointer getTexture(const QUrl& url, image::TextureUsage::Type type = image::TextureUsage::DEFAULT_TEXTURE,
|
||||||
const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
||||||
|
|
||||||
|
|
||||||
gpu::TexturePointer getTextureByHash(const std::string& hash);
|
gpu::TexturePointer getTextureByHash(const std::string& hash);
|
||||||
gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture);
|
gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture);
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
case PacketType::EntityEdit:
|
case PacketType::EntityEdit:
|
||||||
case PacketType::EntityData:
|
case PacketType::EntityData:
|
||||||
case PacketType::EntityPhysics:
|
case PacketType::EntityPhysics:
|
||||||
return static_cast<PacketVersion>(EntityVersion::SoftEntities);
|
return static_cast<PacketVersion>(EntityVersion::MaterialEntities);
|
||||||
case PacketType::EntityQuery:
|
case PacketType::EntityQuery:
|
||||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::RemovedJurisdictions);
|
return static_cast<PacketVersion>(EntityQueryPacketVersion::RemovedJurisdictions);
|
||||||
case PacketType::AvatarIdentity:
|
case PacketType::AvatarIdentity:
|
||||||
|
|
|
@ -217,7 +217,8 @@ enum class EntityVersion : PacketVersion {
|
||||||
OwnershipChallengeFix,
|
OwnershipChallengeFix,
|
||||||
ZoneLightInheritModes = 82,
|
ZoneLightInheritModes = 82,
|
||||||
ZoneStageRemoved,
|
ZoneStageRemoved,
|
||||||
SoftEntities
|
SoftEntities,
|
||||||
|
MaterialEntities
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EntityScriptCallMethodVersion : PacketVersion {
|
enum class EntityScriptCallMethodVersion : PacketVersion {
|
||||||
|
|
|
@ -381,6 +381,17 @@ bool OctreePacketData::appendValue(float value) {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OctreePacketData::appendValue(const glm::vec2& value) {
|
||||||
|
const unsigned char* data = (const unsigned char*)&value;
|
||||||
|
int length = sizeof(value);
|
||||||
|
bool success = append(data, length);
|
||||||
|
if (success) {
|
||||||
|
_bytesOfValues += length;
|
||||||
|
_totalBytesOfValues += length;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
bool OctreePacketData::appendValue(const glm::vec3& value) {
|
bool OctreePacketData::appendValue(const glm::vec3& value) {
|
||||||
const unsigned char* data = (const unsigned char*)&value;
|
const unsigned char* data = (const unsigned char*)&value;
|
||||||
int length = sizeof(value);
|
int length = sizeof(value);
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include <NLPacket.h>
|
#include <NLPacket.h>
|
||||||
#include <udt/PacketHeaders.h>
|
#include <udt/PacketHeaders.h>
|
||||||
|
|
||||||
|
#include "MaterialMappingMode.h"
|
||||||
|
|
||||||
#include "OctreeConstants.h"
|
#include "OctreeConstants.h"
|
||||||
#include "OctreeElement.h"
|
#include "OctreeElement.h"
|
||||||
|
|
||||||
|
@ -162,6 +164,9 @@ public:
|
||||||
/// appends a float value to the end of the stream, may fail if new data stream is too long to fit in packet
|
/// appends a float value to the end of the stream, may fail if new data stream is too long to fit in packet
|
||||||
bool appendValue(float value);
|
bool appendValue(float value);
|
||||||
|
|
||||||
|
/// appends a vec2 to the end of the stream, may fail if new data stream is too long to fit in packet
|
||||||
|
bool appendValue(const glm::vec2& value);
|
||||||
|
|
||||||
/// appends a non-position vector to the end of the stream, may fail if new data stream is too long to fit in packet
|
/// appends a non-position vector to the end of the stream, may fail if new data stream is too long to fit in packet
|
||||||
bool appendValue(const glm::vec3& value);
|
bool appendValue(const glm::vec3& value);
|
||||||
|
|
||||||
|
@ -248,6 +253,7 @@ public:
|
||||||
static quint64 getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color
|
static quint64 getTotalBytesOfColor() { return _totalBytesOfColor; } /// total bytes of color
|
||||||
|
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
|
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
|
@ -257,6 +263,7 @@ public:
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, rgbColor& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, rgbColor& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; }
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
|
static int unpackDataFromBytes(const unsigned char* dataBytes, MaterialMappingMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, QString& result);
|
static int unpackDataFromBytes(const unsigned char* dataBytes, QString& result);
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result);
|
static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result);
|
||||||
static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result);
|
static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result);
|
||||||
|
|
|
@ -38,7 +38,7 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform
|
||||||
_cauterizedTransform = renderTransform;
|
_cauterizedTransform = renderTransform;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
|
||||||
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization;
|
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization;
|
||||||
if (useCauterizedMesh) {
|
if (useCauterizedMesh) {
|
||||||
if (_cauterizedClusterBuffer) {
|
if (_cauterizedClusterBuffer) {
|
||||||
|
@ -46,7 +46,7 @@ void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::S
|
||||||
}
|
}
|
||||||
batch.setModelTransform(_cauterizedTransform);
|
batch.setModelTransform(_cauterizedTransform);
|
||||||
} else {
|
} else {
|
||||||
ModelMeshPartPayload::bindTransform(batch, locations, renderMode);
|
ModelMeshPartPayload::bindTransform(batch, renderMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
|
|
||||||
void updateTransformForCauterizedMesh(const Transform& renderTransform);
|
void updateTransformForCauterizedMesh(const Transform& renderTransform);
|
||||||
|
|
||||||
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
|
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
|
||||||
|
|
||||||
void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; }
|
void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; }
|
||||||
|
|
||||||
|
|
|
@ -1318,7 +1318,6 @@ void GeometryCache::renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, in
|
||||||
renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color, id);
|
renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
|
void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
|
||||||
const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner,
|
const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner,
|
||||||
const glm::vec4& color, int id) {
|
const glm::vec4& color, int id) {
|
||||||
|
|
|
@ -453,6 +453,10 @@ void SelectionToHighlight::run(const render::RenderContextPointer& renderContext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (numLayers == 0) {
|
||||||
|
renderContext->taskFlow.abortTask();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtractSelectionName::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
void ExtractSelectionName::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#include "DeferredLightingEffect.h"
|
#include "DeferredLightingEffect.h"
|
||||||
|
|
||||||
|
#include "RenderPipelines.h"
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
@ -47,7 +49,7 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr
|
||||||
|
|
||||||
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material) {
|
MeshPartPayload::MeshPartPayload(const std::shared_ptr<const graphics::Mesh>& mesh, int partIndex, graphics::MaterialPointer material) {
|
||||||
updateMeshPart(mesh, partIndex);
|
updateMeshPart(mesh, partIndex);
|
||||||
updateMaterial(material);
|
addMaterial(graphics::MaterialLayer(material, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex) {
|
void MeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex) {
|
||||||
|
@ -67,8 +69,12 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor
|
||||||
_worldBound.transform(_drawTransform);
|
_worldBound.transform(_drawTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) {
|
void MeshPartPayload::addMaterial(graphics::MaterialLayer material) {
|
||||||
_drawMaterial = drawMaterial;
|
_drawMaterials.push(material);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) {
|
||||||
|
_drawMaterials.remove(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled) {
|
void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled) {
|
||||||
|
@ -89,8 +95,8 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits,
|
||||||
builder.withSubMetaCulled();
|
builder.withSubMetaCulled();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_drawMaterial) {
|
if (_drawMaterials.top().material) {
|
||||||
auto matKey = _drawMaterial->getKey();
|
auto matKey = _drawMaterials.top().material->getKey();
|
||||||
if (matKey.isTranslucent()) {
|
if (matKey.isTranslucent()) {
|
||||||
builder.withTransparent();
|
builder.withTransparent();
|
||||||
}
|
}
|
||||||
|
@ -109,8 +115,8 @@ Item::Bound MeshPartPayload::getBound() const {
|
||||||
|
|
||||||
ShapeKey MeshPartPayload::getShapeKey() const {
|
ShapeKey MeshPartPayload::getShapeKey() const {
|
||||||
graphics::MaterialKey drawMaterialKey;
|
graphics::MaterialKey drawMaterialKey;
|
||||||
if (_drawMaterial) {
|
if (_drawMaterials.top().material) {
|
||||||
drawMaterialKey = _drawMaterial->getKey();
|
drawMaterialKey = _drawMaterials.top().material->getKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeKey::Builder builder;
|
ShapeKey::Builder builder;
|
||||||
|
@ -143,126 +149,7 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) {
|
||||||
batch.setInputStream(0, _drawMesh->getVertexStream());
|
batch.setInputStream(0, _drawMesh->getVertexStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool enableTextures) const {
|
void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
|
||||||
if (!_drawMaterial) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto textureCache = DependencyManager::get<TextureCache>();
|
|
||||||
|
|
||||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, _drawMaterial->getSchemaBuffer());
|
|
||||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, _drawMaterial->getTexMapArrayBuffer());
|
|
||||||
|
|
||||||
const auto& materialKey = _drawMaterial->getKey();
|
|
||||||
const auto& textureMaps = _drawMaterial->getTextureMaps();
|
|
||||||
|
|
||||||
int numUnlit = 0;
|
|
||||||
if (materialKey.isUnlit()) {
|
|
||||||
numUnlit++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!enableTextures) {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture());
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Albedo
|
|
||||||
if (materialKey.isAlbedoMap()) {
|
|
||||||
auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP);
|
|
||||||
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView());
|
|
||||||
} else {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Roughness map
|
|
||||||
if (materialKey.isRoughnessMap()) {
|
|
||||||
auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP);
|
|
||||||
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView());
|
|
||||||
|
|
||||||
// texcoord are assumed to be the same has albedo
|
|
||||||
} else {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normal map
|
|
||||||
if (materialKey.isNormalMap()) {
|
|
||||||
auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP);
|
|
||||||
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView());
|
|
||||||
|
|
||||||
// texcoord are assumed to be the same has albedo
|
|
||||||
} else {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metallic map
|
|
||||||
if (materialKey.isMetallicMap()) {
|
|
||||||
auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP);
|
|
||||||
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView());
|
|
||||||
|
|
||||||
// texcoord are assumed to be the same has albedo
|
|
||||||
} else {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Occlusion map
|
|
||||||
if (materialKey.isOcclusionMap()) {
|
|
||||||
auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP);
|
|
||||||
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView());
|
|
||||||
|
|
||||||
// texcoord are assumed to be the same has albedo
|
|
||||||
} else {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scattering map
|
|
||||||
if (materialKey.isScatteringMap()) {
|
|
||||||
auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP);
|
|
||||||
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView());
|
|
||||||
|
|
||||||
// texcoord are assumed to be the same has albedo
|
|
||||||
} else {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emissive / Lightmap
|
|
||||||
if (materialKey.isLightmapMap()) {
|
|
||||||
auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP);
|
|
||||||
|
|
||||||
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
|
|
||||||
} else {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture());
|
|
||||||
}
|
|
||||||
} else if (materialKey.isEmissiveMap()) {
|
|
||||||
auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP);
|
|
||||||
|
|
||||||
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
|
|
||||||
} else {
|
|
||||||
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
|
||||||
batch.setModelTransform(_drawTransform);
|
batch.setModelTransform(_drawTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,23 +157,21 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::Loca
|
||||||
void MeshPartPayload::render(RenderArgs* args) {
|
void MeshPartPayload::render(RenderArgs* args) {
|
||||||
PerformanceTimer perfTimer("MeshPartPayload::render");
|
PerformanceTimer perfTimer("MeshPartPayload::render");
|
||||||
|
|
||||||
|
if (!args) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
gpu::Batch& batch = *(args->_batch);
|
gpu::Batch& batch = *(args->_batch);
|
||||||
|
|
||||||
auto locations = args->_shapePipeline->locations;
|
|
||||||
assert(locations);
|
|
||||||
|
|
||||||
// Bind the model transform and the skinCLusterMatrices if needed
|
// Bind the model transform and the skinCLusterMatrices if needed
|
||||||
bindTransform(batch, locations, args->_renderMode);
|
bindTransform(batch, args->_renderMode);
|
||||||
|
|
||||||
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||||
bindMesh(batch);
|
bindMesh(batch);
|
||||||
|
|
||||||
// apply material properties
|
// apply material properties
|
||||||
bindMaterial(batch, locations, args->_enableTexturing);
|
RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing);
|
||||||
|
|
||||||
if (args) {
|
|
||||||
args->_details._materialSwitches++;
|
args->_details._materialSwitches++;
|
||||||
}
|
|
||||||
|
|
||||||
// Draw!
|
// Draw!
|
||||||
{
|
{
|
||||||
|
@ -294,10 +179,8 @@ void MeshPartPayload::render(RenderArgs* args) {
|
||||||
drawCall(batch);
|
drawCall(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args) {
|
|
||||||
const int INDICES_PER_TRIANGLE = 3;
|
const int INDICES_PER_TRIANGLE = 3;
|
||||||
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
@ -379,7 +262,7 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) {
|
||||||
|
|
||||||
auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID);
|
auto networkMaterial = model->getGeometry()->getShapeMaterial(_shapeID);
|
||||||
if (networkMaterial) {
|
if (networkMaterial) {
|
||||||
_drawMaterial = networkMaterial;
|
addMaterial(graphics::MaterialLayer(networkMaterial, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,8 +312,8 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag
|
||||||
builder.withDeformed();
|
builder.withDeformed();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_drawMaterial) {
|
if (_drawMaterials.top().material) {
|
||||||
auto matKey = _drawMaterial->getKey();
|
auto matKey = _drawMaterials.top().material->getKey();
|
||||||
if (matKey.isTranslucent()) {
|
if (matKey.isTranslucent()) {
|
||||||
builder.withTransparent();
|
builder.withTransparent();
|
||||||
}
|
}
|
||||||
|
@ -460,8 +343,8 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics::MaterialKey drawMaterialKey;
|
graphics::MaterialKey drawMaterialKey;
|
||||||
if (_drawMaterial) {
|
if (_drawMaterials.top().material) {
|
||||||
drawMaterialKey = _drawMaterial->getKey();
|
drawMaterialKey = _drawMaterials.top().material->getKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isTranslucent = drawMaterialKey.isTranslucent();
|
bool isTranslucent = drawMaterialKey.isTranslucent();
|
||||||
|
@ -520,7 +403,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
|
||||||
if (_clusterBuffer) {
|
if (_clusterBuffer) {
|
||||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer);
|
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer);
|
||||||
}
|
}
|
||||||
|
@ -535,17 +418,14 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::Batch& batch = *(args->_batch);
|
gpu::Batch& batch = *(args->_batch);
|
||||||
auto locations = args->_shapePipeline->locations;
|
|
||||||
assert(locations);
|
|
||||||
|
|
||||||
bindTransform(batch, locations, args->_renderMode);
|
bindTransform(batch, args->_renderMode);
|
||||||
|
|
||||||
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||||
bindMesh(batch);
|
bindMesh(batch);
|
||||||
|
|
||||||
// apply material properties
|
// apply material properties
|
||||||
bindMaterial(batch, locations, args->_enableTexturing);
|
RenderPipelines::bindMaterial(_drawMaterials.top().material, batch, args->_enableTexturing);
|
||||||
|
|
||||||
args->_details._materialSwitches++;
|
args->_details._materialSwitches++;
|
||||||
|
|
||||||
// Draw!
|
// Draw!
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include <gpu/Batch.h>
|
#include <gpu/Batch.h>
|
||||||
|
|
||||||
#include <render/Scene.h>
|
#include <render/Scene.h>
|
||||||
#include <render/ShapePipeline.h>
|
|
||||||
|
|
||||||
#include <graphics/Geometry.h>
|
#include <graphics/Geometry.h>
|
||||||
|
|
||||||
|
@ -40,8 +39,6 @@ public:
|
||||||
virtual void notifyLocationChanged() {}
|
virtual void notifyLocationChanged() {}
|
||||||
void updateTransform(const Transform& transform, const Transform& offsetTransform);
|
void updateTransform(const Transform& transform, const Transform& offsetTransform);
|
||||||
|
|
||||||
virtual void updateMaterial(graphics::MaterialPointer drawMaterial);
|
|
||||||
|
|
||||||
// Render Item interface
|
// Render Item interface
|
||||||
virtual render::ItemKey getKey() const;
|
virtual render::ItemKey getKey() const;
|
||||||
virtual render::Item::Bound getBound() const;
|
virtual render::Item::Bound getBound() const;
|
||||||
|
@ -51,8 +48,7 @@ public:
|
||||||
// ModelMeshPartPayload functions to perform render
|
// ModelMeshPartPayload functions to perform render
|
||||||
void drawCall(gpu::Batch& batch) const;
|
void drawCall(gpu::Batch& batch) const;
|
||||||
virtual void bindMesh(gpu::Batch& batch);
|
virtual void bindMesh(gpu::Batch& batch);
|
||||||
virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool enableTextures) const;
|
virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const;
|
||||||
virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const;
|
|
||||||
|
|
||||||
// Payload resource cached values
|
// Payload resource cached values
|
||||||
Transform _drawTransform;
|
Transform _drawTransform;
|
||||||
|
@ -65,13 +61,16 @@ public:
|
||||||
mutable graphics::Box _worldBound;
|
mutable graphics::Box _worldBound;
|
||||||
std::shared_ptr<const graphics::Mesh> _drawMesh;
|
std::shared_ptr<const graphics::Mesh> _drawMesh;
|
||||||
|
|
||||||
std::shared_ptr<const graphics::Material> _drawMaterial;
|
graphics::MultiMaterial _drawMaterials;
|
||||||
graphics::Mesh::Part _drawPart;
|
graphics::Mesh::Part _drawPart;
|
||||||
|
|
||||||
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
|
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
|
||||||
size_t getMaterialTextureSize() { return _drawMaterial ? _drawMaterial->getTextureSize() : 0; }
|
size_t getMaterialTextureSize() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureSize() : 0; }
|
||||||
int getMaterialTextureCount() { return _drawMaterial ? _drawMaterial->getTextureCount() : 0; }
|
int getMaterialTextureCount() { return _drawMaterials.top().material ? _drawMaterials.top().material->getTextureCount() : 0; }
|
||||||
bool hasTextureInfo() const { return _drawMaterial ? _drawMaterial->hasTextureInfo() : false; }
|
bool hasTextureInfo() const { return _drawMaterials.top().material ? _drawMaterials.top().material->hasTextureInfo() : false; }
|
||||||
|
|
||||||
|
void addMaterial(graphics::MaterialLayer material);
|
||||||
|
void removeMaterial(graphics::MaterialPointer material);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
|
render::ItemKey _itemKey{ render::ItemKey::Builder::opaqueShape().build() };
|
||||||
|
@ -113,7 +112,7 @@ public:
|
||||||
|
|
||||||
// ModelMeshPartPayload functions to perform render
|
// ModelMeshPartPayload functions to perform render
|
||||||
void bindMesh(gpu::Batch& batch) override;
|
void bindMesh(gpu::Batch& batch) override;
|
||||||
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
|
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
|
||||||
|
|
||||||
void computeAdjustedLocalBound(const std::vector<TransformType>& clusterTransforms);
|
void computeAdjustedLocalBound(const std::vector<TransformType>& clusterTransforms);
|
||||||
|
|
||||||
|
|
|
@ -832,6 +832,7 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti
|
||||||
_modelMeshRenderItemIDs.clear();
|
_modelMeshRenderItemIDs.clear();
|
||||||
_modelMeshRenderItemsMap.clear();
|
_modelMeshRenderItemsMap.clear();
|
||||||
_modelMeshRenderItems.clear();
|
_modelMeshRenderItems.clear();
|
||||||
|
_modelMeshMaterialNames.clear();
|
||||||
_modelMeshRenderItemShapes.clear();
|
_modelMeshRenderItemShapes.clear();
|
||||||
|
|
||||||
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
foreach(auto item, _collisionRenderItemsMap.keys()) {
|
||||||
|
@ -1460,6 +1461,7 @@ void Model::createVisibleRenderItemSet() {
|
||||||
Q_ASSERT(_modelMeshRenderItems.isEmpty());
|
Q_ASSERT(_modelMeshRenderItems.isEmpty());
|
||||||
|
|
||||||
_modelMeshRenderItems.clear();
|
_modelMeshRenderItems.clear();
|
||||||
|
_modelMeshMaterialNames.clear();
|
||||||
_modelMeshRenderItemShapes.clear();
|
_modelMeshRenderItemShapes.clear();
|
||||||
|
|
||||||
Transform transform;
|
Transform transform;
|
||||||
|
@ -1483,6 +1485,7 @@ void Model::createVisibleRenderItemSet() {
|
||||||
int numParts = (int)mesh->getNumParts();
|
int numParts = (int)mesh->getNumParts();
|
||||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||||
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||||
|
_modelMeshMaterialNames.push_back(getGeometry()->getShapeMaterial(shapeID)->getName());
|
||||||
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
|
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
|
||||||
shapeID++;
|
shapeID++;
|
||||||
}
|
}
|
||||||
|
@ -1528,6 +1531,77 @@ bool Model::isRenderable() const {
|
||||||
return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());
|
return !_meshStates.empty() || (isLoaded() && _renderGeometry->getMeshes().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {
|
||||||
|
// try to find all meshes with materials that match parentMaterialName as a string
|
||||||
|
// if none, return parentMaterialName as a uint
|
||||||
|
std::vector<unsigned int> toReturn;
|
||||||
|
const QString MATERIAL_NAME_PREFIX = "mat::";
|
||||||
|
if (parentMaterialName.startsWith(MATERIAL_NAME_PREFIX)) {
|
||||||
|
parentMaterialName.replace(0, MATERIAL_NAME_PREFIX.size(), QString(""));
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)_modelMeshMaterialNames.size(); i++) {
|
||||||
|
if (_modelMeshMaterialNames[i] == parentMaterialName.toStdString()) {
|
||||||
|
toReturn.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toReturn.empty()) {
|
||||||
|
toReturn.push_back(parentMaterialName.toUInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||||
|
std::vector<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
|
||||||
|
render::Transaction transaction;
|
||||||
|
for (auto shapeID : shapeIDs) {
|
||||||
|
if (shapeID < _modelMeshRenderItemIDs.size()) {
|
||||||
|
auto itemID = _modelMeshRenderItemIDs[shapeID];
|
||||||
|
bool visible = isVisible();
|
||||||
|
uint8_t viewTagBits = getViewTagBits();
|
||||||
|
bool layeredInFront = isLayeredInFront();
|
||||||
|
bool layeredInHUD = isLayeredInHUD();
|
||||||
|
bool wireframe = isWireframe();
|
||||||
|
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
|
||||||
|
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
|
||||||
|
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits,
|
||||||
|
invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) {
|
||||||
|
data.addMaterial(material);
|
||||||
|
// if the material changed, we might need to update our item key or shape key
|
||||||
|
data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits);
|
||||||
|
data.setShapeKey(invalidatePayloadShapeKey, wireframe);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) {
|
||||||
|
std::vector<unsigned int> shapeIDs = getMeshIDsFromMaterialID(QString(parentMaterialName.c_str()));
|
||||||
|
render::Transaction transaction;
|
||||||
|
for (auto shapeID : shapeIDs) {
|
||||||
|
if (shapeID < _modelMeshRenderItemIDs.size()) {
|
||||||
|
auto itemID = _modelMeshRenderItemIDs[shapeID];
|
||||||
|
bool visible = isVisible();
|
||||||
|
uint8_t viewTagBits = getViewTagBits();
|
||||||
|
bool layeredInFront = isLayeredInFront();
|
||||||
|
bool layeredInHUD = isLayeredInHUD();
|
||||||
|
bool wireframe = isWireframe();
|
||||||
|
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
|
||||||
|
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
|
||||||
|
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits,
|
||||||
|
invalidatePayloadShapeKey, wireframe](ModelMeshPartPayload& data) {
|
||||||
|
data.removeMaterial(material);
|
||||||
|
// if the material changed, we might need to update our item key or shape key
|
||||||
|
data.updateKey(visible, layeredInFront || layeredInHUD, viewTagBits);
|
||||||
|
data.setShapeKey(invalidatePayloadShapeKey, wireframe);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
class CollisionRenderGeometry : public Geometry {
|
class CollisionRenderGeometry : public Geometry {
|
||||||
public:
|
public:
|
||||||
CollisionRenderGeometry(graphics::MeshPointer mesh) {
|
CollisionRenderGeometry(graphics::MeshPointer mesh) {
|
||||||
|
|
|
@ -320,6 +320,9 @@ public:
|
||||||
|
|
||||||
void scaleToFit();
|
void scaleToFit();
|
||||||
|
|
||||||
|
void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
|
||||||
|
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadURLFinished(bool success);
|
void loadURLFinished(bool success);
|
||||||
|
|
||||||
|
@ -437,6 +440,7 @@ protected:
|
||||||
render::ItemIDs _modelMeshRenderItemIDs;
|
render::ItemIDs _modelMeshRenderItemIDs;
|
||||||
using ShapeInfo = struct { int meshIndex; };
|
using ShapeInfo = struct { int meshIndex; };
|
||||||
std::vector<ShapeInfo> _modelMeshRenderItemShapes;
|
std::vector<ShapeInfo> _modelMeshRenderItemShapes;
|
||||||
|
std::vector<std::string> _modelMeshMaterialNames;
|
||||||
|
|
||||||
bool _addedToScene { false }; // has been added to scene
|
bool _addedToScene { false }; // has been added to scene
|
||||||
bool _needsFixupInScene { true }; // needs to be removed/re-added to scene
|
bool _needsFixupInScene { true }; // needs to be removed/re-added to scene
|
||||||
|
@ -472,6 +476,8 @@ private:
|
||||||
float _loadingPriority { 0.0f };
|
float _loadingPriority { 0.0f };
|
||||||
|
|
||||||
void calculateTextureInfo();
|
void calculateTextureInfo();
|
||||||
|
|
||||||
|
std::vector<unsigned int> getMeshIDsFromMaterialID(QString parentMaterialName);
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(ModelPointer)
|
Q_DECLARE_METATYPE(ModelPointer)
|
||||||
|
|
|
@ -618,3 +618,125 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state) {
|
||||||
ShapeKey::Filter::Builder().withSkinned().withFade(),
|
ShapeKey::Filter::Builder().withSkinned().withFade(),
|
||||||
skinFadeProgram, state);
|
skinFadeProgram, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "RenderPipelines.h"
|
||||||
|
#include <model-networking/TextureCache.h>
|
||||||
|
|
||||||
|
void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) {
|
||||||
|
if (!material) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
|
|
||||||
|
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, material->getSchemaBuffer());
|
||||||
|
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, material->getTexMapArrayBuffer());
|
||||||
|
|
||||||
|
const auto& materialKey = material->getKey();
|
||||||
|
const auto& textureMaps = material->getTextureMaps();
|
||||||
|
|
||||||
|
int numUnlit = 0;
|
||||||
|
if (materialKey.isUnlit()) {
|
||||||
|
numUnlit++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!enableTextures) {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture());
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Albedo
|
||||||
|
if (materialKey.isAlbedoMap()) {
|
||||||
|
auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP);
|
||||||
|
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView());
|
||||||
|
} else {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roughness map
|
||||||
|
if (materialKey.isRoughnessMap()) {
|
||||||
|
auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP);
|
||||||
|
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView());
|
||||||
|
|
||||||
|
// texcoord are assumed to be the same has albedo
|
||||||
|
} else {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal map
|
||||||
|
if (materialKey.isNormalMap()) {
|
||||||
|
auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP);
|
||||||
|
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView());
|
||||||
|
|
||||||
|
// texcoord are assumed to be the same has albedo
|
||||||
|
} else {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metallic map
|
||||||
|
if (materialKey.isMetallicMap()) {
|
||||||
|
auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP);
|
||||||
|
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView());
|
||||||
|
|
||||||
|
// texcoord are assumed to be the same has albedo
|
||||||
|
} else {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Occlusion map
|
||||||
|
if (materialKey.isOcclusionMap()) {
|
||||||
|
auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP);
|
||||||
|
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView());
|
||||||
|
|
||||||
|
// texcoord are assumed to be the same has albedo
|
||||||
|
} else {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scattering map
|
||||||
|
if (materialKey.isScatteringMap()) {
|
||||||
|
auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP);
|
||||||
|
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView());
|
||||||
|
|
||||||
|
// texcoord are assumed to be the same has albedo
|
||||||
|
} else {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emissive / Lightmap
|
||||||
|
if (materialKey.isLightmapMap()) {
|
||||||
|
auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP);
|
||||||
|
|
||||||
|
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
|
||||||
|
} else {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture());
|
||||||
|
}
|
||||||
|
} else if (materialKey.isEmissiveMap()) {
|
||||||
|
auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP);
|
||||||
|
|
||||||
|
if (itr != textureMaps.end() && itr->second->isDefined()) {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
|
||||||
|
} else {
|
||||||
|
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
22
libraries/render-utils/src/RenderPipelines.h
Normal file
22
libraries/render-utils/src/RenderPipelines.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
//
|
||||||
|
// RenderPipelines.h
|
||||||
|
// render-utils/src/
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 2/15/18
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#ifndef hifi_RenderPipelines_h
|
||||||
|
#define hifi_RenderPipelines_h
|
||||||
|
|
||||||
|
#include <graphics/Material.h>
|
||||||
|
|
||||||
|
class RenderPipelines {
|
||||||
|
public:
|
||||||
|
static void bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hifi_RenderPipelines_h
|
24
libraries/shared/src/MaterialMappingMode.cpp
Normal file
24
libraries/shared/src/MaterialMappingMode.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 1/17/2018
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "MaterialMappingMode.h"
|
||||||
|
|
||||||
|
const char* materialMappingModeNames[] = {
|
||||||
|
"uv",
|
||||||
|
"projected"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t MATERIAL_MODE_NAMES = (sizeof(materialMappingModeNames) / sizeof((materialMappingModeNames)[0]));
|
||||||
|
|
||||||
|
QString MaterialMappingModeHelpers::getNameForMaterialMappingMode(MaterialMappingMode mode) {
|
||||||
|
if (((int)mode <= 0) || ((int)mode >= (int)MATERIAL_MODE_NAMES)) {
|
||||||
|
mode = (MaterialMappingMode)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return materialMappingModeNames[(int)mode];
|
||||||
|
}
|
25
libraries/shared/src/MaterialMappingMode.h
Normal file
25
libraries/shared/src/MaterialMappingMode.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//
|
||||||
|
// Created by Sam Gondelman on 1/12/18.
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_MaterialMappingMode_h
|
||||||
|
#define hifi_MaterialMappingMode_h
|
||||||
|
|
||||||
|
#include "QString"
|
||||||
|
|
||||||
|
enum MaterialMappingMode {
|
||||||
|
UV = 0,
|
||||||
|
PROJECTED
|
||||||
|
};
|
||||||
|
|
||||||
|
class MaterialMappingModeHelpers {
|
||||||
|
public:
|
||||||
|
static QString getNameForMaterialMappingMode(MaterialMappingMode mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_MaterialMappingMode_h
|
||||||
|
|
|
@ -256,6 +256,13 @@ namespace std {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<QString> {
|
||||||
|
size_t operator()(const QString& a) const {
|
||||||
|
return qHash(a);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ContactEventType {
|
enum ContactEventType {
|
||||||
|
|
35
libraries/task/src/task/Task.cpp
Normal file
35
libraries/task/src/task/Task.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
//
|
||||||
|
// Task.cpp
|
||||||
|
// task/src/task
|
||||||
|
//
|
||||||
|
// Created by Sam Gateau on 2/14/2018.
|
||||||
|
// Copyright 2018 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
#include "Task.h"
|
||||||
|
|
||||||
|
using namespace task;
|
||||||
|
|
||||||
|
JobContext::JobContext(const QLoggingCategory& category) :
|
||||||
|
profileCategory(category) {
|
||||||
|
assert(&category);
|
||||||
|
}
|
||||||
|
|
||||||
|
JobContext::~JobContext() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskFlow::reset() {
|
||||||
|
_doAbortTask = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskFlow::abortTask() {
|
||||||
|
_doAbortTask = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TaskFlow::doAbortTask() const {
|
||||||
|
return _doAbortTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,15 +27,44 @@ template <class JC> class JobT;
|
||||||
template <class JC> class TaskT;
|
template <class JC> class TaskT;
|
||||||
class JobNoIO {};
|
class JobNoIO {};
|
||||||
|
|
||||||
|
// Task Flow control class is a simple per value object used to communicate flow control commands trhough the graph of tasks.
|
||||||
|
// From within the Job::Run function, you can access it from the JobCOntext and issue commands which will be picked up by the Task calling for the Job run.
|
||||||
|
// This is first introduced to provide a way to abort all the work from within a task job. see the "abortTask" call
|
||||||
|
class TaskFlow {
|
||||||
|
public:
|
||||||
|
// A job that wants to abort the rest of the other jobs execution in a task would issue that call "abortTask" and let the task early exit for this run.
|
||||||
|
// All the varyings produced by the aborted branch of jobs are left unmodified.
|
||||||
|
void abortTask();
|
||||||
|
|
||||||
|
// called by the task::run to perform flow control
|
||||||
|
// This should be considered private but still need to be accessible from the Task<T> class
|
||||||
|
TaskFlow() = default;
|
||||||
|
~TaskFlow() = default;
|
||||||
|
void reset();
|
||||||
|
bool doAbortTask() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool _doAbortTask{ false };
|
||||||
|
};
|
||||||
|
|
||||||
|
// JobContext class is the base calss for the context object which is passed through all the Job::run calls thoughout the graph of jobs
|
||||||
|
// It is used to communicate to the job::run its context and various state information the job relies on.
|
||||||
|
// It specifically provide access to:
|
||||||
|
// - The taskFlow object allowing for messaging control flow commands from within a Job::run
|
||||||
|
// - The current Config object attached to the Job::run currently called.
|
||||||
|
// The JobContext can be derived to add more global state to it that Jobs can access
|
||||||
class JobContext {
|
class JobContext {
|
||||||
public:
|
public:
|
||||||
JobContext(const QLoggingCategory& category) : profileCategory(category) {
|
JobContext(const QLoggingCategory& category);
|
||||||
assert(&category);
|
virtual ~JobContext();
|
||||||
}
|
|
||||||
virtual ~JobContext() {}
|
|
||||||
|
|
||||||
std::shared_ptr<JobConfig> jobConfig { nullptr };
|
std::shared_ptr<JobConfig> jobConfig { nullptr };
|
||||||
const QLoggingCategory& profileCategory;
|
const QLoggingCategory& profileCategory;
|
||||||
|
|
||||||
|
// Task flow control
|
||||||
|
TaskFlow taskFlow{};
|
||||||
|
|
||||||
|
protected:
|
||||||
};
|
};
|
||||||
using JobContextPointer = std::shared_ptr<JobContext>;
|
using JobContextPointer = std::shared_ptr<JobContext>;
|
||||||
|
|
||||||
|
@ -308,6 +337,10 @@ public:
|
||||||
if (config->alwaysEnabled || config->enabled) {
|
if (config->alwaysEnabled || config->enabled) {
|
||||||
for (auto job : TaskConcept::_jobs) {
|
for (auto job : TaskConcept::_jobs) {
|
||||||
job.run(jobContext);
|
job.run(jobContext);
|
||||||
|
if (jobContext->taskFlow.doAbortTask()) {
|
||||||
|
jobContext->taskFlow.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -340,10 +340,11 @@ class InputDialogListener : public ModalDialogListener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connect(_dialog, SIGNAL(selected(QVariant)), this, SLOT(onSelected(const QVariant&)));
|
connect(_dialog, SIGNAL(selected(QVariant)), this, SLOT(onSelected(const QVariant&)));
|
||||||
|
connect(_dialog, SIGNAL(canceled()), this, SLOT(onSelected()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onSelected(const QVariant& result) {
|
void onSelected(const QVariant& result = "") {
|
||||||
_result = result;
|
_result = result;
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
emit response(_result);
|
emit response(_result);
|
||||||
|
@ -698,10 +699,11 @@ class FileDialogListener : public ModalDialogListener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connect(_dialog, SIGNAL(selectedFile(QVariant)), this, SLOT(onSelectedFile(QVariant)));
|
connect(_dialog, SIGNAL(selectedFile(QVariant)), this, SLOT(onSelectedFile(QVariant)));
|
||||||
|
connect(_dialog, SIGNAL(canceled()), this, SLOT(onSelectedFile()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onSelectedFile(QVariant file) {
|
void onSelectedFile(QVariant file = "") {
|
||||||
_result = file.toUrl().toLocalFile();
|
_result = file.toUrl().toLocalFile();
|
||||||
_finished = true;
|
_finished = true;
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
|
@ -947,10 +949,11 @@ class AssetDialogListener : public ModalDialogListener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connect(_dialog, SIGNAL(selectedAsset(QVariant)), this, SLOT(onSelectedAsset(QVariant)));
|
connect(_dialog, SIGNAL(selectedAsset(QVariant)), this, SLOT(onSelectedAsset(QVariant)));
|
||||||
|
connect(_dialog, SIGNAL(canceled()), this, SLOT(onSelectedAsset()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onSelectedAsset(QVariant asset) {
|
void onSelectedAsset(QVariant asset = "") {
|
||||||
_result = asset;
|
_result = asset;
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
emit response(_result);
|
emit response(_result);
|
||||||
|
|
|
@ -11,7 +11,8 @@ var toolBar = (function() {
|
||||||
newTextButton,
|
newTextButton,
|
||||||
newWebButton,
|
newWebButton,
|
||||||
newZoneButton,
|
newZoneButton,
|
||||||
newParticleButton
|
newParticleButton,
|
||||||
|
newMaterialButton
|
||||||
|
|
||||||
var toolIconUrl = Script.resolvePath("../../system/assets/images/tools/");
|
var toolIconUrl = Script.resolvePath("../../system/assets/images/tools/");
|
||||||
|
|
||||||
|
@ -89,6 +90,13 @@ var toolBar = (function() {
|
||||||
visible: false
|
visible: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
newMaterialButton = toolBar.addButton({
|
||||||
|
objectName: "newMaterialButton",
|
||||||
|
imageURL: toolIconUrl + "material-01.svg",
|
||||||
|
alpha: 0.9,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
|
||||||
that.setActive(false);
|
that.setActive(false);
|
||||||
newModelButton.clicked();
|
newModelButton.clicked();
|
||||||
}
|
}
|
||||||
|
@ -109,8 +117,8 @@ var toolBar = (function() {
|
||||||
newTextButton.writeProperty('visible', doShow);
|
newTextButton.writeProperty('visible', doShow);
|
||||||
newWebButton.writeProperty('visible', doShow);
|
newWebButton.writeProperty('visible', doShow);
|
||||||
newZoneButton.writeProperty('visible', doShow);
|
newZoneButton.writeProperty('visible', doShow);
|
||||||
newModelButton.writeProperty('visible', doShow);
|
|
||||||
newParticleButton.writeProperty('visible', doShow);
|
newParticleButton.writeProperty('visible', doShow);
|
||||||
|
newMaterialButton.writeProperty('visible', doShow);
|
||||||
};
|
};
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
|
|
|
@ -251,8 +251,7 @@ var toolBar = (function () {
|
||||||
// Align entity with Avatar orientation.
|
// Align entity with Avatar orientation.
|
||||||
properties.rotation = MyAvatar.orientation;
|
properties.rotation = MyAvatar.orientation;
|
||||||
|
|
||||||
var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web"];
|
var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web", "Material"];
|
||||||
|
|
||||||
if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) {
|
if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) {
|
||||||
|
|
||||||
// Adjust position of entity per bounding box prior to creating it.
|
// Adjust position of entity per bounding box prior to creating it.
|
||||||
|
@ -343,7 +342,7 @@ var toolBar = (function () {
|
||||||
|
|
||||||
var buttonHandlers = {}; // only used to tablet mode
|
var buttonHandlers = {}; // only used to tablet mode
|
||||||
|
|
||||||
function addButton(name, image, handler) {
|
function addButton(name, handler) {
|
||||||
buttonHandlers[name] = handler;
|
buttonHandlers[name] = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,6 +354,9 @@ var toolBar = (function () {
|
||||||
var SHAPE_TYPE_SPHERE = 5;
|
var SHAPE_TYPE_SPHERE = 5;
|
||||||
var DYNAMIC_DEFAULT = false;
|
var DYNAMIC_DEFAULT = false;
|
||||||
|
|
||||||
|
var MATERIAL_MODE_UV = 0;
|
||||||
|
var MATERIAL_MODE_PROJECTED = 1;
|
||||||
|
|
||||||
function handleNewModelDialogResult(result) {
|
function handleNewModelDialogResult(result) {
|
||||||
if (result) {
|
if (result) {
|
||||||
var url = result.textInput;
|
var url = result.textInput;
|
||||||
|
@ -395,6 +397,30 @@ var toolBar = (function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleNewMaterialDialogResult(result) {
|
||||||
|
if (result) {
|
||||||
|
var materialURL = result.textInput;
|
||||||
|
//var materialMappingMode;
|
||||||
|
//switch (result.comboBox) {
|
||||||
|
// case MATERIAL_MODE_PROJECTED:
|
||||||
|
// materialMappingMode = "projected";
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// shapeType = "uv";
|
||||||
|
//}
|
||||||
|
|
||||||
|
var DEFAULT_LAYERED_MATERIAL_PRIORITY = 1;
|
||||||
|
if (materialURL) {
|
||||||
|
createNewEntity({
|
||||||
|
type: "Material",
|
||||||
|
materialURL: materialURL,
|
||||||
|
//materialMappingMode: materialMappingMode,
|
||||||
|
priority: DEFAULT_LAYERED_MATERIAL_PRIORITY
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
|
function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
tablet.popFromStack();
|
tablet.popFromStack();
|
||||||
|
@ -405,6 +431,9 @@ var toolBar = (function () {
|
||||||
case "newEntityButtonClicked":
|
case "newEntityButtonClicked":
|
||||||
buttonHandlers[message.params.buttonName]();
|
buttonHandlers[message.params.buttonName]();
|
||||||
break;
|
break;
|
||||||
|
case "newMaterialDialogAdd":
|
||||||
|
handleNewMaterialDialogResult(message.params);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,32 +477,22 @@ var toolBar = (function () {
|
||||||
that.toggle();
|
that.toggle();
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("importEntitiesButton", "assets-01.svg", function() {
|
addButton("importEntitiesButton", function() {
|
||||||
Window.browseChanged.connect(onFileOpenChanged);
|
Window.browseChanged.connect(onFileOpenChanged);
|
||||||
Window.browseAsync("Select Model to Import", "", "*.json");
|
Window.browseAsync("Select Model to Import", "", "*.json");
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("openAssetBrowserButton", "assets-01.svg", function() {
|
addButton("openAssetBrowserButton", function() {
|
||||||
Window.showAssetServer();
|
Window.showAssetServer();
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newModelButton", "model-01.svg", function () {
|
addButton("newModelButton", function () {
|
||||||
|
|
||||||
var SHAPE_TYPES = [];
|
|
||||||
SHAPE_TYPES[SHAPE_TYPE_NONE] = "No Collision";
|
|
||||||
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_HULL] = "Basic - Whole model";
|
|
||||||
SHAPE_TYPES[SHAPE_TYPE_SIMPLE_COMPOUND] = "Good - Sub-meshes";
|
|
||||||
SHAPE_TYPES[SHAPE_TYPE_STATIC_MESH] = "Exact - All polygons";
|
|
||||||
SHAPE_TYPES[SHAPE_TYPE_BOX] = "Box";
|
|
||||||
SHAPE_TYPES[SHAPE_TYPE_SPHERE] = "Sphere";
|
|
||||||
var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH;
|
|
||||||
|
|
||||||
// tablet version of new-model dialog
|
// tablet version of new-model dialog
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml");
|
tablet.pushOntoStack("hifi/tablet/NewModelDialog.qml");
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newCubeButton", "cube-01.svg", function () {
|
addButton("newCubeButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Box",
|
type: "Box",
|
||||||
dimensions: DEFAULT_DIMENSIONS,
|
dimensions: DEFAULT_DIMENSIONS,
|
||||||
|
@ -485,7 +504,7 @@ var toolBar = (function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newSphereButton", "sphere-01.svg", function () {
|
addButton("newSphereButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Sphere",
|
type: "Sphere",
|
||||||
dimensions: DEFAULT_DIMENSIONS,
|
dimensions: DEFAULT_DIMENSIONS,
|
||||||
|
@ -497,7 +516,7 @@ var toolBar = (function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newLightButton", "light-01.svg", function () {
|
addButton("newLightButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Light",
|
type: "Light",
|
||||||
dimensions: DEFAULT_LIGHT_DIMENSIONS,
|
dimensions: DEFAULT_LIGHT_DIMENSIONS,
|
||||||
|
@ -516,7 +535,7 @@ var toolBar = (function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newTextButton", "text-01.svg", function () {
|
addButton("newTextButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Text",
|
type: "Text",
|
||||||
dimensions: {
|
dimensions: {
|
||||||
|
@ -539,7 +558,7 @@ var toolBar = (function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newImageButton", "web-01.svg", function () {
|
addButton("newImageButton", function () {
|
||||||
var IMAGE_MODEL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx";
|
var IMAGE_MODEL = "https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx";
|
||||||
var DEFAULT_IMAGE = "https://hifi-content.s3.amazonaws.com/DomainContent/production/no-image.jpg";
|
var DEFAULT_IMAGE = "https://hifi-content.s3.amazonaws.com/DomainContent/production/no-image.jpg";
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
|
@ -555,7 +574,7 @@ var toolBar = (function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newWebButton", "web-01.svg", function () {
|
addButton("newWebButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Web",
|
type: "Web",
|
||||||
dimensions: {
|
dimensions: {
|
||||||
|
@ -567,7 +586,7 @@ var toolBar = (function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newZoneButton", "zone-01.svg", function () {
|
addButton("newZoneButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "Zone",
|
type: "Zone",
|
||||||
dimensions: {
|
dimensions: {
|
||||||
|
@ -578,7 +597,7 @@ var toolBar = (function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
addButton("newParticleButton", "particle-01.svg", function () {
|
addButton("newParticleButton", function () {
|
||||||
createNewEntity({
|
createNewEntity({
|
||||||
type: "ParticleEffect",
|
type: "ParticleEffect",
|
||||||
isEmitting: true,
|
isEmitting: true,
|
||||||
|
@ -631,6 +650,12 @@ var toolBar = (function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addButton("newMaterialButton", function () {
|
||||||
|
// tablet version of new material dialog
|
||||||
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
tablet.pushOntoStack("hifi/tablet/NewMaterialDialog.qml");
|
||||||
|
});
|
||||||
|
|
||||||
that.setActive(false);
|
that.setActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1999,7 +2024,7 @@ var PropertiesTool = function (opts) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Entities.editEntity(selectionManager.selections[0], data.properties);
|
Entities.editEntity(selectionManager.selections[0], data.properties);
|
||||||
if (data.properties.name !== undefined || data.properties.modelURL !== undefined ||
|
if (data.properties.name !== undefined || data.properties.modelURL !== undefined || data.properties.materialURL !== undefined ||
|
||||||
data.properties.visible !== undefined || data.properties.locked !== undefined) {
|
data.properties.visible !== undefined || data.properties.locked !== undefined) {
|
||||||
entityListTool.sendUpdate();
|
entityListTool.sendUpdate();
|
||||||
}
|
}
|
||||||
|
@ -2010,7 +2035,7 @@ var PropertiesTool = function (opts) {
|
||||||
parentSelectedEntities();
|
parentSelectedEntities();
|
||||||
} else if (data.type === 'unparent') {
|
} else if (data.type === 'unparent') {
|
||||||
unparentSelectedEntities();
|
unparentSelectedEntities();
|
||||||
} else if (data.type === 'saveUserData'){
|
} else if (data.type === 'saveUserData') {
|
||||||
//the event bridge and json parsing handle our avatar id string differently.
|
//the event bridge and json parsing handle our avatar id string differently.
|
||||||
var actualID = data.id.split('"')[1];
|
var actualID = data.id.split('"')[1];
|
||||||
Entities.editEntity(actualID, data.properties);
|
Entities.editEntity(actualID, data.properties);
|
||||||
|
|
|
@ -448,12 +448,10 @@ input[type=checkbox]:checked + label:hover {
|
||||||
border: 1.5pt solid black;
|
border: 1.5pt solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shape-section, .light-section, .model-section, .web-section, .image-section, .hyperlink-section, .text-section, .zone-section {
|
.shape-section, .light-section, .model-section, .web-section, .image-section, .hyperlink-section, .text-section, .zone-section, .material-section {
|
||||||
display: table;
|
display: table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#properties-list fieldset {
|
#properties-list fieldset {
|
||||||
position: relative;
|
position: relative;
|
||||||
/* 0.1px on the top is to prevent margin collapsing between this and it's first child */
|
/* 0.1px on the top is to prevent margin collapsing between this and it's first child */
|
||||||
|
@ -571,6 +569,7 @@ hr {
|
||||||
.physical-group[collapsed="true"] ~ .physical-group,
|
.physical-group[collapsed="true"] ~ .physical-group,
|
||||||
.behavior-group[collapsed="true"] ~ .behavior-group,
|
.behavior-group[collapsed="true"] ~ .behavior-group,
|
||||||
.model-group[collapsed="true"] ~ .model-group,
|
.model-group[collapsed="true"] ~ .model-group,
|
||||||
|
.material-group[collapsed="true"] ~ .material-group,
|
||||||
.light-group[collapsed="true"] ~ .light-group {
|
.light-group[collapsed="true"] ~ .light-group {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
@ -645,14 +644,14 @@ hr {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text label, .url label, .number label, .textarea label, .rgb label, .xyz label, .pyr label, .dropdown label, .gen label {
|
.text label, .url label, .number label, .textarea label, .xy label, .wh label, .rgb label, .xyz label,.pyr label, .dropdown label, .gen label {
|
||||||
float: left;
|
float: left;
|
||||||
margin-left: 1px;
|
margin-left: 1px;
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
margin-top: -2px;
|
margin-top: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text legend, .url legend, .number legend, .textarea legend, .rgb legend, .xyz legend, .pyr legend, .dropdown legend, .gen legend {
|
.text legend, .url legend, .number legend, .textarea legend, .xy legend, .wh legend, .rgb legend, .xyz legend, .pyr legend, .dropdown legend, .gen legend {
|
||||||
float: left;
|
float: left;
|
||||||
margin-left: 1px;
|
margin-left: 1px;
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
|
@ -667,7 +666,7 @@ hr {
|
||||||
clear: both;
|
clear: both;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
.xyz > div, .pyr > div, .gen > div {
|
.xy > div, .wh > div, .xyz > div, .pyr > div, .gen > div {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,6 +840,12 @@ div.refresh input[type="button"] {
|
||||||
margin-right: -6px;
|
margin-right: -6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.xy .tuple input {
|
||||||
|
padding-left: 25px;
|
||||||
|
}
|
||||||
|
.wh .tuple input {
|
||||||
|
padding-left: 45px;
|
||||||
|
}
|
||||||
.rgb .tuple input {
|
.rgb .tuple input {
|
||||||
padding-left: 65px;
|
padding-left: 65px;
|
||||||
}
|
}
|
||||||
|
@ -1387,7 +1392,7 @@ input#reset-to-natural-dimensions {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#static-userdata{
|
#static-userdata {
|
||||||
display: none;
|
display: none;
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -1398,7 +1403,7 @@ input#reset-to-natural-dimensions {
|
||||||
background-color: #2e2e2e;
|
background-color: #2e2e2e;
|
||||||
}
|
}
|
||||||
|
|
||||||
#userdata-saved{
|
#userdata-saved {
|
||||||
margin-top:5px;
|
margin-top:5px;
|
||||||
font-size:16px;
|
font-size:16px;
|
||||||
display:none;
|
display:none;
|
||||||
|
@ -1455,6 +1460,9 @@ input#reset-to-natural-dimensions {
|
||||||
order: 6;
|
order: 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#properties-list.ShapeMenu #material,
|
||||||
|
#properties-list.BoxMenu #material,
|
||||||
|
#properties-list.SphereMenu #material,
|
||||||
#properties-list.ShapeMenu #light,
|
#properties-list.ShapeMenu #light,
|
||||||
#properties-list.BoxMenu #light,
|
#properties-list.BoxMenu #light,
|
||||||
#properties-list.SphereMenu #light,
|
#properties-list.SphereMenu #light,
|
||||||
|
@ -1494,6 +1502,7 @@ input#reset-to-natural-dimensions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* items to hide */
|
/* items to hide */
|
||||||
|
#properties-list.ParticleEffectMenu #material,
|
||||||
#properties-list.ParticleEffectMenu #base-color-section,
|
#properties-list.ParticleEffectMenu #base-color-section,
|
||||||
#properties-list.ParticleEffectMenu #hyperlink,
|
#properties-list.ParticleEffectMenu #hyperlink,
|
||||||
#properties-list.ParticleEffectMenu #light,
|
#properties-list.ParticleEffectMenu #light,
|
||||||
|
@ -1529,6 +1538,7 @@ input#reset-to-natural-dimensions {
|
||||||
order: 7;
|
order: 7;
|
||||||
}
|
}
|
||||||
/* sections to hide */
|
/* sections to hide */
|
||||||
|
#properties-list.LightMenu #material,
|
||||||
#properties-list.LightMenu #model,
|
#properties-list.LightMenu #model,
|
||||||
#properties-list.LightMenu #zone,
|
#properties-list.LightMenu #zone,
|
||||||
#properties-list.LightMenu #text,
|
#properties-list.LightMenu #text,
|
||||||
|
@ -1566,6 +1576,7 @@ input#reset-to-natural-dimensions {
|
||||||
order: 7;
|
order: 7;
|
||||||
}
|
}
|
||||||
/* sections to hide */
|
/* sections to hide */
|
||||||
|
#properties-list.ModelMenu #material,
|
||||||
#properties-list.ModelMenu #light,
|
#properties-list.ModelMenu #light,
|
||||||
#properties-list.ModelMenu #zone,
|
#properties-list.ModelMenu #zone,
|
||||||
#properties-list.ModelMenu #text,
|
#properties-list.ModelMenu #text,
|
||||||
|
@ -1603,6 +1614,7 @@ input#reset-to-natural-dimensions {
|
||||||
order: 7;
|
order: 7;
|
||||||
}
|
}
|
||||||
/* sections to hide */
|
/* sections to hide */
|
||||||
|
#properties-list.ZoneMenu #material,
|
||||||
#properties-list.ZoneMenu #light,
|
#properties-list.ZoneMenu #light,
|
||||||
#properties-list.ZoneMenu #model,
|
#properties-list.ZoneMenu #model,
|
||||||
#properties-list.ZoneMenu #text,
|
#properties-list.ZoneMenu #text,
|
||||||
|
@ -1640,6 +1652,7 @@ input#reset-to-natural-dimensions {
|
||||||
order: 7;
|
order: 7;
|
||||||
}
|
}
|
||||||
/* sections to hide */
|
/* sections to hide */
|
||||||
|
#properties-list.ImageMenu #material,
|
||||||
#properties-list.ImageMenu #light,
|
#properties-list.ImageMenu #light,
|
||||||
#properties-list.ImageMenu #model,
|
#properties-list.ImageMenu #model,
|
||||||
#properties-list.ImageMenu #zone,
|
#properties-list.ImageMenu #zone,
|
||||||
|
@ -1677,6 +1690,7 @@ input#reset-to-natural-dimensions {
|
||||||
order: 7;
|
order: 7;
|
||||||
}
|
}
|
||||||
/* sections to hide */
|
/* sections to hide */
|
||||||
|
#properties-list.WebMenu #material,
|
||||||
#properties-list.WebMenu #light,
|
#properties-list.WebMenu #light,
|
||||||
#properties-list.WebMenu #model,
|
#properties-list.WebMenu #model,
|
||||||
#properties-list.WebMenu #zone,
|
#properties-list.WebMenu #zone,
|
||||||
|
@ -1715,6 +1729,7 @@ input#reset-to-natural-dimensions {
|
||||||
order: 7;
|
order: 7;
|
||||||
}
|
}
|
||||||
/* sections to hide */
|
/* sections to hide */
|
||||||
|
#properties-list.TextMenu #material,
|
||||||
#properties-list.TextMenu #light,
|
#properties-list.TextMenu #light,
|
||||||
#properties-list.TextMenu #model,
|
#properties-list.TextMenu #model,
|
||||||
#properties-list.TextMenu #zone,
|
#properties-list.TextMenu #zone,
|
||||||
|
@ -1728,6 +1743,40 @@ input#reset-to-natural-dimensions {
|
||||||
display: none
|
display: none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----- Order of Menu items for Material ----- */
|
||||||
|
#properties-list.MaterialMenu #general {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
#properties-list.MaterialMenu #material {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
#properties-list.MaterialMenu #spatial {
|
||||||
|
order: 3;
|
||||||
|
}
|
||||||
|
#properties-list.MaterialMenu #hyperlink {
|
||||||
|
order: 4;
|
||||||
|
}
|
||||||
|
#properties-list.MaterialMenu #behavior {
|
||||||
|
order: 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sections to hide */
|
||||||
|
#properties-list.MaterialMenu #physical,
|
||||||
|
#properties-list.MaterialMenu #collision-info,
|
||||||
|
#properties-list.MaterialMenu #model,
|
||||||
|
#properties-list.MaterialMenu #light,
|
||||||
|
#properties-list.MaterialMenu #zone,
|
||||||
|
#properties-list.MaterialMenu #text,
|
||||||
|
#properties-list.MaterialMenu #web,
|
||||||
|
#properties-list.MaterialMenu #image {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* items to hide */
|
||||||
|
#properties-list.MaterialMenu #shape-list,
|
||||||
|
#properties-list.MaterialMenu #base-color-section {
|
||||||
|
display: none
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Currently always hidden */
|
/* Currently always hidden */
|
||||||
#properties-list #polyvox {
|
#properties-list #polyvox {
|
||||||
|
|
|
@ -770,6 +770,71 @@
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset id="material" class="major">
|
||||||
|
<legend class="section-header material-group material-section">
|
||||||
|
Material<span>M</span>
|
||||||
|
</legend>
|
||||||
|
<fieldset class="minor">
|
||||||
|
<div class="material-group material-section property url">
|
||||||
|
<label for="property-material-url">Material URL</label>
|
||||||
|
<input type="text" id="property-material-url">
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="minor">
|
||||||
|
<div class="material-group material-section property text" id="property-parent-material-id-string-container">
|
||||||
|
<label for="property-parent-material-id-string">Material Name to Replace </label>
|
||||||
|
<input type="text" id="property-parent-material-id-string">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="material-group material-section property number" id="property-parent-material-id-number-container">
|
||||||
|
<label for="property-parent-material-id-number">Submesh to Replace </label>
|
||||||
|
<input type="number" min="0" step="1" value="0" id="property-parent-material-id-number">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="material-group material-section property checkbox">
|
||||||
|
<input type="checkbox" id="property-parent-material-id-checkbox">
|
||||||
|
<label for="property-parent-material-id-checkbox">Select Submesh</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="material-group material-section property number">
|
||||||
|
<label>Priority </label>
|
||||||
|
<input type="number" id="property-priority" min="0">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<!-- TODO: support 3D projected materials
|
||||||
|
<div class="material-group material-section property dropdown">
|
||||||
|
<label>Material mode </label>
|
||||||
|
<select name="SelectMaterialMode" id="property-material-mapping-mode">
|
||||||
|
<option value="uv">UV space material</option>
|
||||||
|
<option value="projected">3D projected material</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<div class="material-group material-section property xy fstuple">
|
||||||
|
<label>Material Position </label>
|
||||||
|
<div class="tuple">
|
||||||
|
<div><input type="number" class="x" id="property-material-mapping-pos-x" min="0" max="1" step="0.1"><label for="property-material-mapping-pos-x">X:</label></div>
|
||||||
|
<div><input type="number" class="y" id="property-material-mapping-pos-y" min="0" max="1" step="0.1"><label for="property-material-mapping-pos-y">Y:</label></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="material-group material-section property wh fstuple">
|
||||||
|
<label>Material Scale </label>
|
||||||
|
<div class="tuple">
|
||||||
|
<div><input type="number" class="x" id="property-material-mapping-scale-x" min="0" step="0.1"><label for="property-material-mapping-scale-x">Width:</label></div>
|
||||||
|
<div><input type="number" class="y" id="property-material-mapping-scale-y" min="0" step="0.1"><label for="property-material-mapping-scale-y">Height:</label></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="material-group material-section property number">
|
||||||
|
<label>Material Rotation <span class="unit">deg</span></label>
|
||||||
|
<input type="number" id="property-material-mapping-rot" step="0.1">
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@ var ICON_FOR_TYPE = {
|
||||||
Zone: "o",
|
Zone: "o",
|
||||||
PolyVox: "",
|
PolyVox: "",
|
||||||
Multiple: "",
|
Multiple: "",
|
||||||
PolyLine: ""
|
PolyLine: "",
|
||||||
|
Material: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
var EDITOR_TIMEOUT_DURATION = 1500;
|
var EDITOR_TIMEOUT_DURATION = 1500;
|
||||||
|
@ -33,6 +34,8 @@ var KEY_P = 80; // Key code for letter p used for Parenting hotkey.
|
||||||
var colorPickers = [];
|
var colorPickers = [];
|
||||||
var lastEntityID = null;
|
var lastEntityID = null;
|
||||||
|
|
||||||
|
var MATERIAL_PREFIX_STRING = "mat::";
|
||||||
|
|
||||||
function debugPrint(message) {
|
function debugPrint(message) {
|
||||||
EventBridge.emitWebEvent(
|
EventBridge.emitWebEvent(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
@ -78,7 +81,6 @@ function disableProperties() {
|
||||||
if ($('#userdata-editor').css('display') === "block" && elLocked.checked === true) {
|
if ($('#userdata-editor').css('display') === "block" && elLocked.checked === true) {
|
||||||
showStaticUserData();
|
showStaticUserData();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showElements(els, show) {
|
function showElements(els, show) {
|
||||||
|
@ -174,6 +176,17 @@ function createEmitGroupTextPropertyUpdateFunction(group, propertyName) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createEmitVec2PropertyUpdateFunction(property, elX, elY) {
|
||||||
|
return function () {
|
||||||
|
var properties = {};
|
||||||
|
properties[property] = {
|
||||||
|
x: elX.value,
|
||||||
|
y: elY.value
|
||||||
|
};
|
||||||
|
updateProperties(properties);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) {
|
function createEmitVec3PropertyUpdateFunction(property, elX, elY, elZ) {
|
||||||
return function() {
|
return function() {
|
||||||
var properties = {};
|
var properties = {};
|
||||||
|
@ -480,7 +493,6 @@ function bindAllNonJSONEditorElements() {
|
||||||
} else {
|
} else {
|
||||||
if ($('#userdata-editor').css('height') !== "0px") {
|
if ($('#userdata-editor').css('height') !== "0px") {
|
||||||
saveJSONUserData(true);
|
saveJSONUserData(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -506,6 +518,18 @@ function clearSelection() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showParentMaterialNameBox(number, elNumber, elString) {
|
||||||
|
if (number) {
|
||||||
|
$('#property-parent-material-id-number-container').show();
|
||||||
|
$('#property-parent-material-id-string-container').hide();
|
||||||
|
elString.value = "";
|
||||||
|
} else {
|
||||||
|
$('#property-parent-material-id-string-container').show();
|
||||||
|
$('#property-parent-material-id-number-container').hide();
|
||||||
|
elNumber.value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function loaded() {
|
function loaded() {
|
||||||
openEventBridge(function() {
|
openEventBridge(function() {
|
||||||
|
|
||||||
|
@ -628,6 +652,18 @@ function loaded() {
|
||||||
var elModelTextures = document.getElementById("property-model-textures");
|
var elModelTextures = document.getElementById("property-model-textures");
|
||||||
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
|
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
|
||||||
|
|
||||||
|
var elMaterialURL = document.getElementById("property-material-url");
|
||||||
|
//var elMaterialMappingMode = document.getElementById("property-material-mapping-mode");
|
||||||
|
var elPriority = document.getElementById("property-priority");
|
||||||
|
var elParentMaterialNameString = document.getElementById("property-parent-material-id-string");
|
||||||
|
var elParentMaterialNameNumber = document.getElementById("property-parent-material-id-number");
|
||||||
|
var elParentMaterialNameCheckbox = document.getElementById("property-parent-material-id-checkbox");
|
||||||
|
var elMaterialMappingPosX = document.getElementById("property-material-mapping-pos-x");
|
||||||
|
var elMaterialMappingPosY = document.getElementById("property-material-mapping-pos-y");
|
||||||
|
var elMaterialMappingScaleX = document.getElementById("property-material-mapping-scale-x");
|
||||||
|
var elMaterialMappingScaleY = document.getElementById("property-material-mapping-scale-y");
|
||||||
|
var elMaterialMappingRot = document.getElementById("property-material-mapping-rot");
|
||||||
|
|
||||||
var elImageURL = document.getElementById("property-image-url");
|
var elImageURL = document.getElementById("property-image-url");
|
||||||
|
|
||||||
var elWebSourceURL = document.getElementById("property-web-source-url");
|
var elWebSourceURL = document.getElementById("property-web-source-url");
|
||||||
|
@ -1127,6 +1163,25 @@ function loaded() {
|
||||||
elXTextureURL.value = properties.xTextureURL;
|
elXTextureURL.value = properties.xTextureURL;
|
||||||
elYTextureURL.value = properties.yTextureURL;
|
elYTextureURL.value = properties.yTextureURL;
|
||||||
elZTextureURL.value = properties.zTextureURL;
|
elZTextureURL.value = properties.zTextureURL;
|
||||||
|
} else if (properties.type === "Material") {
|
||||||
|
elMaterialURL.value = properties.materialURL;
|
||||||
|
//elMaterialMappingMode.value = properties.materialMappingMode;
|
||||||
|
//setDropdownText(elMaterialMappingMode);
|
||||||
|
elPriority.value = properties.priority;
|
||||||
|
if (properties.parentMaterialName.startsWith(MATERIAL_PREFIX_STRING)) {
|
||||||
|
elParentMaterialNameString.value = properties.parentMaterialName.replace(MATERIAL_PREFIX_STRING, "");
|
||||||
|
showParentMaterialNameBox(false, elParentMaterialNameNumber, elParentMaterialNameString);
|
||||||
|
elParentMaterialNameCheckbox.checked = false;
|
||||||
|
} else {
|
||||||
|
elParentMaterialNameNumber.value = parseInt(properties.parentMaterialName);
|
||||||
|
showParentMaterialNameBox(true, elParentMaterialNameNumber, elParentMaterialNameString);
|
||||||
|
elParentMaterialNameCheckbox.checked = true;
|
||||||
|
}
|
||||||
|
elMaterialMappingPosX.value = properties.materialMappingPos.x.toFixed(4);
|
||||||
|
elMaterialMappingPosY.value = properties.materialMappingPos.y.toFixed(4);
|
||||||
|
elMaterialMappingScaleX.value = properties.materialMappingScale.x.toFixed(4);
|
||||||
|
elMaterialMappingScaleY.value = properties.materialMappingScale.y.toFixed(4);
|
||||||
|
elMaterialMappingRot.value = properties.materialMappingRot.toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (properties.locked) {
|
if (properties.locked) {
|
||||||
|
@ -1399,6 +1454,30 @@ function loaded() {
|
||||||
|
|
||||||
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
||||||
|
|
||||||
|
elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL'));
|
||||||
|
//elMaterialMappingMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMappingMode'));
|
||||||
|
elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority', 0));
|
||||||
|
|
||||||
|
elParentMaterialNameString.addEventListener('change', function () { updateProperty("parentMaterialName", MATERIAL_PREFIX_STRING + this.value); });
|
||||||
|
elParentMaterialNameNumber.addEventListener('change', function () { updateProperty("parentMaterialName", this.value); });
|
||||||
|
elParentMaterialNameCheckbox.addEventListener('change', function () {
|
||||||
|
if (this.checked) {
|
||||||
|
updateProperty("parentMaterialName", elParentMaterialNameNumber.value);
|
||||||
|
showParentMaterialNameBox(true, elParentMaterialNameNumber, elParentMaterialNameString);
|
||||||
|
} else {
|
||||||
|
updateProperty("parentMaterialName", MATERIAL_PREFIX_STRING + elParentMaterialNameString.value);
|
||||||
|
showParentMaterialNameBox(false, elParentMaterialNameNumber, elParentMaterialNameString);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var materialMappingPosChangeFunction = createEmitVec2PropertyUpdateFunction('materialMappingPos', elMaterialMappingPosX, elMaterialMappingPosY);
|
||||||
|
elMaterialMappingPosX.addEventListener('change', materialMappingPosChangeFunction);
|
||||||
|
elMaterialMappingPosY.addEventListener('change', materialMappingPosChangeFunction);
|
||||||
|
var materialMappingScaleChangeFunction = createEmitVec2PropertyUpdateFunction('materialMappingScale', elMaterialMappingScaleX, elMaterialMappingScaleY);
|
||||||
|
elMaterialMappingScaleX.addEventListener('change', materialMappingScaleChangeFunction);
|
||||||
|
elMaterialMappingScaleY.addEventListener('change', materialMappingScaleChangeFunction);
|
||||||
|
elMaterialMappingRot.addEventListener('change', createEmitNumberPropertyUpdateFunction('materialMappingRot', 2));
|
||||||
|
|
||||||
elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text'));
|
elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text'));
|
||||||
elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera'));
|
elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera'));
|
||||||
elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight'));
|
elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight'));
|
||||||
|
|
|
@ -77,18 +77,24 @@ EntityListTool = function(opts) {
|
||||||
var properties = Entities.getEntityProperties(id);
|
var properties = Entities.getEntityProperties(id);
|
||||||
|
|
||||||
if (!filterInView || Vec3.distance(properties.position, cameraPosition) <= searchRadius) {
|
if (!filterInView || Vec3.distance(properties.position, cameraPosition) <= searchRadius) {
|
||||||
|
var url = "";
|
||||||
|
if (properties.type == "Model") {
|
||||||
|
url = properties.modelURL;
|
||||||
|
} else if (properties.type == "Material") {
|
||||||
|
url = properties.materialURL;
|
||||||
|
}
|
||||||
entities.push({
|
entities.push({
|
||||||
id: id,
|
id: id,
|
||||||
name: properties.name,
|
name: properties.name,
|
||||||
type: properties.type,
|
type: properties.type,
|
||||||
url: properties.type == "Model" ? properties.modelURL : "",
|
url: url,
|
||||||
locked: properties.locked,
|
locked: properties.locked,
|
||||||
visible: properties.visible,
|
visible: properties.visible,
|
||||||
verticesCount: valueIfDefined(properties.renderInfo.verticesCount),
|
verticesCount: valueIfDefined(properties.renderInfo.verticesCount),
|
||||||
texturesCount: valueIfDefined(properties.renderInfo.texturesCount),
|
texturesCount: valueIfDefined(properties.renderInfo.texturesCount),
|
||||||
texturesSize: valueIfDefined(properties.renderInfo.texturesSize),
|
texturesSize: valueIfDefined(properties.renderInfo.texturesSize),
|
||||||
hasTransparent: valueIfDefined(properties.renderInfo.hasTransparent),
|
hasTransparent: valueIfDefined(properties.renderInfo.hasTransparent),
|
||||||
isBaked: properties.type == "Model" ? properties.modelURL.toLowerCase().endsWith(".baked.fbx") : false,
|
isBaked: properties.type == "Model" ? url.toLowerCase().endsWith(".baked.fbx") : false,
|
||||||
drawCalls: valueIfDefined(properties.renderInfo.drawCalls),
|
drawCalls: valueIfDefined(properties.renderInfo.drawCalls),
|
||||||
hasScript: properties.script !== ""
|
hasScript: properties.script !== ""
|
||||||
});
|
});
|
||||||
|
|
|
@ -1018,6 +1018,7 @@ SelectionDisplay = (function() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (SelectionManager.hasSelection()) {
|
if (SelectionManager.hasSelection()) {
|
||||||
var position = SelectionManager.worldPosition;
|
var position = SelectionManager.worldPosition;
|
||||||
var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation;
|
var rotation = spaceMode === SPACE_LOCAL ? SelectionManager.localRotation : SelectionManager.worldRotation;
|
||||||
|
@ -1317,8 +1318,12 @@ SelectionDisplay = (function() {
|
||||||
isActiveTool(handleScaleRTNCube) || isActiveTool(handleScaleLTFCube) ||
|
isActiveTool(handleScaleRTNCube) || isActiveTool(handleScaleLTFCube) ||
|
||||||
isActiveTool(handleScaleRTFCube) || isActiveTool(handleStretchXSphere) ||
|
isActiveTool(handleScaleRTFCube) || isActiveTool(handleStretchXSphere) ||
|
||||||
isActiveTool(handleStretchYSphere) || isActiveTool(handleStretchZSphere));
|
isActiveTool(handleStretchYSphere) || isActiveTool(handleStretchZSphere));
|
||||||
that.setHandleScaleEdgeVisible(!isActiveTool(handleRotatePitchRing) && !isActiveTool(handleRotateYawRing) &&
|
|
||||||
!isActiveTool(handleRotateRollRing));
|
var showOutlineForZone = (SelectionManager.selections.length === 1 &&
|
||||||
|
SelectionManager.savedProperties[SelectionManager.selections[0]].type === "Zone");
|
||||||
|
that.setHandleScaleEdgeVisible(showOutlineForZone || (!isActiveTool(handleRotatePitchRing) &&
|
||||||
|
!isActiveTool(handleRotateYawRing) &&
|
||||||
|
!isActiveTool(handleRotateRollRing)));
|
||||||
|
|
||||||
//keep cloner always hidden for now since you can hold Alt to clone while
|
//keep cloner always hidden for now since you can hold Alt to clone while
|
||||||
//translating an entity - we may bring cloner back for HMD only later
|
//translating an entity - we may bring cloner back for HMD only later
|
||||||
|
|
Loading…
Reference in a new issue