Merge branch 'master' of https://github.com/highfidelity/hifi into blue

This commit is contained in:
samcake 2017-10-25 13:14:47 -07:00
commit 5b0bbbb21e
59 changed files with 885 additions and 502 deletions

View file

@ -14,6 +14,12 @@
var isWindowFocused = true;
var isKeyboardRaised = false;
var isNumericKeyboard = false;
var isPasswordField = false;
function shouldSetPasswordField() {
var nodeType = document.activeElement.type;
return nodeType === "password";
}
function shouldRaiseKeyboard() {
var nodeName = document.activeElement.nodeName;
@ -53,12 +59,14 @@
setInterval(function () {
var keyboardRaised = shouldRaiseKeyboard();
var numericKeyboard = shouldSetNumeric();
var passwordField = shouldSetPasswordField();
if (isWindowFocused && (keyboardRaised !== isKeyboardRaised || numericKeyboard !== isNumericKeyboard)) {
if (isWindowFocused &&
(keyboardRaised !== isKeyboardRaised || numericKeyboard !== isNumericKeyboard || passwordField !== isPasswordField)) {
if (typeof EventBridge !== "undefined" && EventBridge !== null) {
EventBridge.emitWebEvent(
keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "")) : "_LOWER_KEYBOARD"
keyboardRaised ? ("_RAISE_KEYBOARD" + (numericKeyboard ? "_NUMERIC" : "") + (passwordField ? "_PASSWORD" : "")) : "_LOWER_KEYBOARD"
);
} else {
if (numWarnings < MAX_WARNINGS) {
@ -74,6 +82,7 @@
isKeyboardRaised = keyboardRaised;
isNumericKeyboard = numericKeyboard;
isPasswordField = passwordField;
}
}, POLL_FREQUENCY);

View file

@ -119,6 +119,7 @@ Item {
width: parent.width
focus: true
label: "Username or Email"
activeFocusOnPress: true
ShortcutText {
anchors {
@ -135,6 +136,9 @@ Item {
onLinkActivated: loginDialog.openUrl(link)
}
onFocusChanged: {
root.text = "";
}
}
TextField {
@ -143,6 +147,7 @@ Item {
label: "Password"
echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password
activeFocusOnPress: true
ShortcutText {
anchors {
@ -159,6 +164,10 @@ Item {
onLinkActivated: loginDialog.openUrl(link)
}
onFocusChanged: {
root.text = "";
root.isPassword = true;
}
}
CheckBoxQQC2 {
@ -233,18 +242,6 @@ Item {
}
}
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
Keyboard {
raised: keyboardEnabled && keyboardRaised
numeric: punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
}
}
Component.onCompleted: {
root.title = qsTr("Sign Into High Fidelity")
root.iconText = "<"

View file

@ -108,12 +108,17 @@ Item {
id: emailField
width: parent.width
label: "Email"
activeFocusOnPress: true
onFocusChanged: {
root.text = "";
}
}
TextField {
id: usernameField
width: parent.width
label: "Username"
activeFocusOnPress: true
ShortcutText {
anchors {
@ -128,6 +133,9 @@ Item {
horizontalAlignment: Text.AlignHCenter
color: hifi.colors.blueAccent
onFocusChanged: {
root.text = "";
}
}
}
@ -136,6 +144,7 @@ Item {
width: parent.width
label: "Password"
echoMode: TextInput.Password
activeFocusOnPress: true
ShortcutText {
anchors {
@ -151,6 +160,11 @@ Item {
color: hifi.colors.blueAccent
}
onFocusChanged: {
root.text = "";
root.isPassword = focus
}
}
Row {
@ -202,18 +216,6 @@ Item {
}
}
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
Keyboard {
raised: keyboardEnabled && keyboardRaised
numeric: punctuationMode
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
}
}
Component.onCompleted: {
root.title = qsTr("Create an Account")
root.iconText = "<"

View file

@ -39,6 +39,10 @@ Rectangle {
property bool shiftMode: false
property bool numericShiftMode: false
onRaisedChanged: {
mirroredText = "";
}
function resetShiftMode(mode) {
shiftMode = mode;
shiftKey.resetToggledMode(mode);

View file

@ -16,6 +16,7 @@ Item {
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
property bool passwordField: false
property bool isDesktop: false
property alias webView: web.webViewCore
property alias profile: web.webViewCoreProfile
@ -41,7 +42,7 @@ Item {
horizontalCenter: parent.horizontalCenter
}
spacing: 120
TabletWebButton {
id: back
enabledColor: hifi.colors.darkGray
@ -165,6 +166,11 @@ Item {
id: keyboard
raised: parent.keyboardEnabled && parent.keyboardRaised
numeric: parent.punctuationMode
password: parent.passwordField
onPasswordChanged: {
keyboard.mirroredText = "";
}
anchors {
left: parent.left
@ -172,7 +178,7 @@ Item {
bottom: parent.bottom
}
}
Component.onCompleted: {
root.isDesktop = (typeof desktop !== "undefined");
keyboardEnabled = HMD.active;

View file

@ -13,6 +13,7 @@ Item {
property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false
property bool keyboardRaised: false
property bool punctuationMode: false
property bool passwordField: false
property alias flickable: webroot.interactive
// FIXME - Keyboard HMD only: Make Interface either set keyboardRaised property directly in OffscreenQmlSurface
@ -50,6 +51,7 @@ Item {
id: keyboard
raised: parent.keyboardEnabled && parent.keyboardRaised
numeric: parent.punctuationMode
password: parent.passwordField
anchors {
left: parent.left
right: parent.right

View file

@ -37,6 +37,8 @@ TabletModalWindow {
property bool keyboardEnabled: false
property bool keyboardRaised: false
property bool punctuationMode: false
property bool isPassword: false
property alias text: loginKeyboard.mirroredText
readonly property bool isTablet: true
@ -130,6 +132,7 @@ TabletModalWindow {
id: loginKeyboard
raised: root.keyboardEnabled && root.keyboardRaised
numeric: root.punctuationMode
password: root.isPassword
anchors {
left: parent.left
right: parent.right

View file

@ -39,7 +39,8 @@ Rectangle {
property bool itemIsJson: true;
property bool shouldBuyWithControlledFailure: false;
property bool debugCheckoutSuccess: false;
property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified;
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
property bool isWearable;
// Style
color: hifi.colors.white;
Hifi.QmlCommerce {
@ -80,6 +81,7 @@ Rectangle {
root.activeView = "checkoutFailure";
} else {
root.itemHref = result.data.download_url;
root.isWearable = result.data.categories.indexOf("Wearables") > -1;
root.activeView = "checkoutSuccess";
}
}
@ -592,7 +594,7 @@ Rectangle {
height: 50;
anchors.left: parent.left;
anchors.right: parent.right;
text: "Rez It"
text: root.isWearable ? "Wear It" : "Rez It"
onClicked: {
if (urlHandler.canHandleUrl(root.itemHref)) {
urlHandler.handleUrl(root.itemHref);
@ -603,7 +605,7 @@ Rectangle {
}
RalewaySemiBold {
id: noPermissionText;
visible: !root.canRezCertifiedItems;
visible: !root.canRezCertifiedItems && !root.isWearable;
text: '<font color="' + hifi.colors.redAccent + '"><a href="#">You do not have Certified Rez permissions in this domain.</a></font>'
// Text size
size: 16;

View file

@ -39,6 +39,7 @@ Item {
property int itemEdition;
property int numberSold;
property int limitedRun;
property bool isWearable;
property string originalStatusText;
property string originalStatusColor;
@ -342,7 +343,7 @@ Item {
anchors.bottom: parent.bottom;
anchors.right: parent.right;
width: height;
enabled: root.canRezCertifiedItems && root.purchaseStatus !== "invalidated";
enabled: (root.canRezCertifiedItems || root.isWearable) && root.purchaseStatus !== "invalidated";
onClicked: {
if (urlHandler.canHandleUrl(root.itemHref)) {
@ -415,7 +416,7 @@ Item {
size: 16;
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: "Rez It"
text: root.isWearable ? "Wear It" : "Rez It"
}
}
}

View file

@ -32,7 +32,7 @@ Rectangle {
property bool securityImageResultReceived: false;
property bool purchasesReceived: false;
property bool punctuationMode: false;
property bool canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified;
property bool canRezCertifiedItems: Entities.canRezCertified() || Entities.canRezTmpCertified();
property bool pendingInventoryReply: true;
property bool isShowingMyItems: false;
property bool isDebuggingFirstUseTutorial: false;
@ -434,6 +434,7 @@ Rectangle {
numberSold: model.number_sold;
limitedRun: model.limited_run;
displayedItemCount: model.displayedItemCount;
isWearable: model.categories.indexOf("Wearables") > -1;
anchors.topMargin: 12;
anchors.bottomMargin: 12;
@ -582,9 +583,11 @@ Rectangle {
Timer {
id: inventoryTimer;
interval: 90000;
interval: 4000; // Change this back to 90000 after demo
//interval: 90000;
onTriggered: {
if (root.activeView === "purchasesMain" && !root.pendingInventoryReply) {
console.log("Refreshing Purchases...");
root.pendingInventoryReply = true;
commerce.inventory();
}
@ -660,6 +663,8 @@ Rectangle {
currentPurchasesModelStatus !== previousPurchasesModelStatus) {
purchasesModel.setProperty(i, "statusChanged", true);
} else {
purchasesModel.setProperty(i, "statusChanged", false);
}
}
}

View file

@ -27,6 +27,7 @@ Item {
id: root;
z: 997;
property bool keyboardRaised: false;
property bool isPasswordField: false;
property string titleBarIcon: "";
property string titleBarText: "";
@ -202,6 +203,7 @@ Item {
onFocusChanged: {
root.keyboardRaised = focus;
root.isPasswordField = (focus && passphraseField.echoMode === TextInput.Password);
}
MouseArea {
@ -209,6 +211,7 @@ Item {
onClicked: {
root.keyboardRaised = true;
root.isPasswordField = (passphraseField.echoMode === TextInput.Password);
mouse.accepted = false;
}
}
@ -382,6 +385,7 @@ Item {
id: keyboard;
raised: HMD.mounted && root.keyboardRaised;
numeric: parent.punctuationMode;
password: root.isPasswordField;
anchors {
bottom: parent.bottom;
left: parent.left;

View file

@ -80,16 +80,18 @@ Item {
onFocusChanged: {
if (focus) {
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
var hidePassword = (currentPassphraseField.echoMode === TextInput.Password);
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
} else if (!passphraseFieldAgain.focus) {
sendSignalToWallet({method: 'walletSetup_lowerKeyboard'});
sendSignalToWallet({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
}
}
MouseArea {
anchors.fill: parent;
onPressed: {
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
var hidePassword = (currentPassphraseField.echoMode === TextInput.Password);
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
mouse.accepted = false;
}
}
@ -116,16 +118,18 @@ Item {
MouseArea {
anchors.fill: parent;
onPressed: {
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
var hidePassword = (passphraseField.echoMode === TextInput.Password);
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
mouse.accepted = false;
}
}
onFocusChanged: {
if (focus) {
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'});
var hidePassword = (passphraseField.echoMode === TextInput.Password);
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
} else if (!passphraseFieldAgain.focus) {
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'});
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
}
}
@ -150,16 +154,18 @@ Item {
MouseArea {
anchors.fill: parent;
onPressed: {
sendSignalToWallet({method: 'walletSetup_raiseKeyboard'});
var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password);
sendSignalToWallet({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
mouse.accepted = false;
}
}
onFocusChanged: {
if (focus) {
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard'});
var hidePassword = (passphraseFieldAgain.echoMode === TextInput.Password);
sendMessageToLightbox({method: 'walletSetup_raiseKeyboard', isPasswordField: hidePassword});
} else if (!passphraseField.focus) {
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard'});
sendMessageToLightbox({method: 'walletSetup_lowerKeyboard', isPasswordField: false});
}
}

View file

@ -29,6 +29,7 @@ Rectangle {
property string activeView: "initialize";
property bool keyboardRaised: false;
property bool isPassword: false;
Image {
anchors.fill: parent;
@ -181,8 +182,10 @@ Rectangle {
}
} else if (msg.method === 'walletSetup_raiseKeyboard') {
root.keyboardRaised = true;
root.isPassword = msg.isPasswordField;
} else if (msg.method === 'walletSetup_lowerKeyboard') {
root.keyboardRaised = false;
root.isPassword = msg.isPasswordField;
} else {
sendToScript(msg);
}
@ -202,6 +205,7 @@ Rectangle {
onSendSignalToWallet: {
if (msg.method === 'walletSetup_raiseKeyboard') {
root.keyboardRaised = true;
root.isPassword = msg.isPasswordField;
} else if (msg.method === 'walletSetup_lowerKeyboard') {
root.keyboardRaised = false;
} else if (msg.method === 'walletSecurity_changePassphraseCancelled') {
@ -685,6 +689,7 @@ Rectangle {
id: keyboard;
raised: HMD.mounted && root.keyboardRaised;
numeric: parent.punctuationMode;
password: root.isPassword;
anchors {
bottom: parent.bottom;
left: parent.left;

View file

@ -43,6 +43,7 @@ Item {
calculatePendingAndInvalidated();
}
refreshTimer.start();
}
}
@ -117,6 +118,8 @@ Item {
historyReceived = false;
commerce.balance();
commerce.history();
} else {
refreshTimer.stop();
}
}
}
@ -138,6 +141,17 @@ Item {
}
}
Timer {
id: refreshTimer;
interval: 4000; // Remove this after demo?
onTriggered: {
console.log("Refreshing Wallet Home...");
historyReceived = false;
commerce.balance();
commerce.history();
}
}
// Recent Activity
Rectangle {
id: recentActivityContainer;

View file

@ -120,6 +120,7 @@
#include <SceneScriptingInterface.h>
#include <ScriptEngines.h>
#include <ScriptCache.h>
#include <ShapeEntityItem.h>
#include <SoundCache.h>
#include <ui/TabletScriptingInterface.h>
#include <ui/ToolbarScriptingInterface.h>
@ -4228,6 +4229,10 @@ void Application::init() {
// fire off an immediate domain-server check in now that settings are loaded
DependencyManager::get<NodeList>()->sendDomainServerCheckIn();
// This allows collision to be set up properly for shape entities supported by GeometryCache.
// This is before entity setup to ensure that it's ready for whenever instance collision is initialized.
ShapeEntityItem::setShapeInfoCalulator(ShapeEntityItem::ShapeInfoCalculator(&shapeInfoCalculator));
getEntities()->init();
getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) {
auto dims = item.getDimensions();

View file

@ -28,6 +28,8 @@
#include <GeometryCache.h>
#include <OctreeConstants.h>
#include <SharedUtil.h>
#include <ShapeEntityItem.h>
#include <ShapeInfo.h>
#include "InterfaceLogging.h"
#include "world.h"
@ -393,4 +395,20 @@ void runUnitTests() {
}
}
void shapeInfoCalculator(const ShapeEntityItem * const shapeEntity, ShapeInfo &shapeInfo) {
if (shapeEntity == nullptr) {
//--EARLY EXIT--
return;
}
ShapeInfo::PointCollection pointCollection;
ShapeInfo::PointList points;
pointCollection.push_back(points);
GeometryCache::computeSimpleHullPointListForShape((int)shapeEntity->getShape(), shapeEntity->getDimensions(), pointCollection.back());
shapeInfo.setPointCollection(pointCollection);
}

View file

@ -18,6 +18,9 @@
#include <gpu/Batch.h>
#include <render/Forward.h>
class ShapeEntityItem;
class ShapeInfo;
void renderWorldBox(RenderArgs* args, gpu::Batch& batch);
void runTimingTests();
@ -28,4 +31,6 @@ bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNorma
bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadius);
void shapeInfoCalculator(const ShapeEntityItem * const shapeEntity, ShapeInfo &shapeInfo);
#endif // hifi_Util_h

View file

@ -587,14 +587,16 @@ void MyAvatar::simulate(float deltaTime) {
MovingEntitiesOperator moveOperator;
forEachDescendant([&](SpatiallyNestablePointer object) {
// if the queryBox has changed, tell the entity-server
if (object->getNestableType() == NestableType::Entity && object->checkAndMaybeUpdateQueryAACube()) {
if (object->getNestableType() == NestableType::Entity && object->updateQueryAACube()) {
EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);
bool success;
AACube newCube = entity->getQueryAACube(success);
if (success) {
moveOperator.addEntityToMoveList(entity, newCube);
}
if (packetSender) {
// send an edit packet to update the entity-server about the queryAABox. If it's an
// avatar-entity, don't.
if (packetSender && !entity->getClientOnly()) {
EntityItemProperties properties = entity->getProperties();
properties.setQueryAACubeDirty();
properties.setLastEdited(now);

View file

@ -140,8 +140,8 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID&
if (event.getID() == LEFT_HAND_HW_ID) {
offsetAngle *= -1.0f;
}
contextOverlayPosition = (glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f)))) *
((cameraPosition + direction * (distance - CONTEXT_OVERLAY_OFFSET_DISTANCE)));
contextOverlayPosition = cameraPosition +
(glm::quat(glm::radians(glm::vec3(0.0f, offsetAngle, 0.0f)))) * (direction * (distance - CONTEXT_OVERLAY_OFFSET_DISTANCE));
contextOverlayDimensions = glm::vec2(CONTEXT_OVERLAY_SIZE, CONTEXT_OVERLAY_SIZE) * glm::distance(contextOverlayPosition, cameraPosition);
}

View file

@ -72,7 +72,7 @@ void JSBaker::bake() {
bool JSBaker::bakeJS(const QByteArray& inputFile, QByteArray& outputFile) {
// Read from inputFile and write to outputFile per character
QTextStream in(inputFile, QIODevice::ReadOnly);
QTextStream out(outputFile, QIODevice::WriteOnly);
QTextStream out(&outputFile, QIODevice::WriteOnly);
// Algorithm requires the knowledge of previous and next character for each character read
QChar currentCharacter;

View file

@ -234,7 +234,8 @@ void CompositorHelper::handleLeaveEvent() {
bool CompositorHelper::handleRealMouseMoveEvent(bool sendFakeEvent) {
// If the mouse move came from a capture mouse related move, we completely ignore it.
if (_ignoreMouseMove) {
// Note: if not going to synthesize event - do not touch _ignoreMouseMove flag
if (_ignoreMouseMove && sendFakeEvent) {
_ignoreMouseMove = false;
return true; // swallow the event
}
@ -246,7 +247,12 @@ bool CompositorHelper::handleRealMouseMoveEvent(bool sendFakeEvent) {
auto changeInRealMouse = newPosition - _lastKnownRealMouse;
auto newReticlePosition = _reticlePositionInHMD + toGlm(changeInRealMouse);
setReticlePosition(newReticlePosition, sendFakeEvent);
_ignoreMouseMove = true;
// Note: if not going to synthesize event - do not touch _ignoreMouseMove flag
if (sendFakeEvent) {
_ignoreMouseMove = true;
}
QCursor::setPos(QPoint(_lastKnownRealMouse.x(), _lastKnownRealMouse.y())); // move cursor back to where it was
return true; // swallow the event
} else {

View file

@ -418,6 +418,19 @@ void OpenGLDisplayPlugin::customizeContext() {
_hudPipeline = gpu::Pipeline::create(program, state);
}
{
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
auto ps = gpu::StandardShaderLib::getDrawTextureMirroredXPS();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::makeProgram(*program);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(false));
state->setBlendFunction(true,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_mirrorHUDPipeline = gpu::Pipeline::create(program, state);
}
{
auto vs = gpu::StandardShaderLib::getDrawTransformUnitQuadVS();
auto ps = gpu::StandardShaderLib::getDrawTexturePS();
@ -438,6 +451,7 @@ void OpenGLDisplayPlugin::uncustomizeContext() {
_presentPipeline.reset();
_cursorPipeline.reset();
_hudPipeline.reset();
_mirrorHUDPipeline.reset();
_compositeFramebuffer.reset();
withPresentThreadLock([&] {
_currentFrame.reset();
@ -562,11 +576,11 @@ void OpenGLDisplayPlugin::updateFrameData() {
});
}
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> OpenGLDisplayPlugin::getHUDOperator() {
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture) {
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> OpenGLDisplayPlugin::getHUDOperator() {
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) {
if (_hudPipeline) {
batch.enableStereo(false);
batch.setPipeline(_hudPipeline);
batch.setPipeline(mirror ? _mirrorHUDPipeline : _hudPipeline);
batch.setResourceTexture(0, hudTexture);
if (isStereo()) {
for_each_eye([&](Eye eye) {

View file

@ -95,7 +95,7 @@ protected:
virtual QThread::Priority getPresentPriority() { return QThread::HighPriority; }
virtual void compositeLayers();
virtual void compositeScene();
virtual std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator();
virtual std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> getHUDOperator();
virtual void compositePointer();
virtual void compositeExtra() {};
@ -140,6 +140,8 @@ protected:
gpu::Frame* _lastFrame { nullptr };
gpu::FramebufferPointer _compositeFramebuffer;
gpu::PipelinePointer _hudPipeline;
gpu::PipelinePointer _mirrorHUDPipeline;
gpu::ShaderPointer _mirrorHUDPS;
gpu::PipelinePointer _simplePipeline;
gpu::PipelinePointer _presentPipeline;
gpu::PipelinePointer _cursorPipeline;

View file

@ -419,9 +419,9 @@ void HmdDisplayPlugin::HUDRenderer::updatePipeline() {
}
}
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> HmdDisplayPlugin::HUDRenderer::render(HmdDisplayPlugin& plugin) {
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> HmdDisplayPlugin::HUDRenderer::render(HmdDisplayPlugin& plugin) {
updatePipeline();
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture) {
return [this](gpu::Batch& batch, const gpu::TexturePointer& hudTexture, bool mirror) {
if (pipeline) {
batch.setPipeline(pipeline);
@ -436,7 +436,11 @@ std::function<void(gpu::Batch&, const gpu::TexturePointer&)> HmdDisplayPlugin::H
batch.setUniformBuffer(uniformsLocation, uniformsBuffer);
auto compositorHelper = DependencyManager::get<CompositorHelper>();
batch.setModelTransform(compositorHelper->getUiTransform());
glm::mat4 modelTransform = compositorHelper->getUiTransform();
if (mirror) {
modelTransform = glm::scale(modelTransform, glm::vec3(-1, 1, 1));
}
batch.setModelTransform(modelTransform);
batch.setResourceTexture(0, hudTexture);
batch.drawIndexed(gpu::TRIANGLES, indexCount);
@ -468,7 +472,7 @@ void HmdDisplayPlugin::compositePointer() {
});
}
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> HmdDisplayPlugin::getHUDOperator() {
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> HmdDisplayPlugin::getHUDOperator() {
return _hudRenderer.render(*this);
}

View file

@ -53,7 +53,7 @@ protected:
bool internalActivate() override;
void internalDeactivate() override;
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator() override;
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> getHUDOperator() override;
void compositePointer() override;
void internalPresent() override;
void customizeContext() override;
@ -116,6 +116,6 @@ private:
void build();
void updatePipeline();
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> render(HmdDisplayPlugin& plugin);
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> render(HmdDisplayPlugin& plugin);
} _hudRenderer;
};

View file

@ -695,12 +695,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) {
const void* key = static_cast<const void*>(shape);
if (_collisionMeshKey != key) {
if (_collisionMeshKey) {
collisionMeshCache.releaseMesh(_collisionMeshKey);
}
_collisionMeshKey = key;
// toggle _showCollisionGeometry forces re-evaluation later
_showCollisionGeometry = !_showCollisionGeometry;
emit requestCollisionGeometryUpdate();
}
}
@ -1103,6 +1099,10 @@ bool ModelEntityRenderer::needsRenderUpdate() const {
if (model->getRenderItemsNeedUpdate()) {
return true;
}
if (_needsCollisionGeometryUpdate) {
return true;
}
}
return Parent::needsRenderUpdate();
}
@ -1169,6 +1169,15 @@ bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoin
return false;
}
void ModelEntityRenderer::setCollisionMeshKey(const void*key) {
if (key != _collisionMeshKey) {
if (_collisionMeshKey) {
collisionMeshCache.releaseMesh(_collisionMeshKey);
}
_collisionMeshKey = key;
}
}
void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
DETAILED_PROFILE_RANGE(simulation_physics, __FUNCTION__);
if (_hasModel != entity->hasModel()) {
@ -1201,6 +1210,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
model = std::make_shared<Model>(nullptr, entity.get());
connect(model.get(), &Model::setURLFinished, this, &ModelEntityRenderer::requestRenderUpdate);
connect(model.get(), &Model::requestRenderUpdate, this, &ModelEntityRenderer::requestRenderUpdate);
connect(entity.get(), &RenderableModelEntityItem::requestCollisionGeometryUpdate, this, &ModelEntityRenderer::flagForCollisionGeometryUpdate);
model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity));
model->init();
entity->setModel(model);
@ -1259,6 +1269,26 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
// TODO? early exit here when not visible?
if (_needsCollisionGeometryUpdate) {
setCollisionMeshKey(entity->getCollisionMeshKey());
_needsCollisionGeometryUpdate = false;
ShapeType type = entity->getShapeType();
if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) {
// NOTE: it is OK if _collisionMeshKey is nullptr
model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey);
// NOTE: the model will render the collisionGeometry if it has one
_model->setCollisionMesh(mesh);
} else {
if (_collisionMeshKey) {
// release mesh
collisionMeshCache.releaseMesh(_collisionMeshKey);
}
// clear model's collision geometry
model::MeshPointer mesh = nullptr;
_model->setCollisionMesh(mesh);
}
}
{
DETAILED_PROFILE_RANGE(simulation_physics, "Fixup");
if (model->needsFixupInScene()) {
@ -1297,6 +1327,11 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
}
void ModelEntityRenderer::flagForCollisionGeometryUpdate() {
_needsCollisionGeometryUpdate = true;
emit requestRenderUpdate();
}
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items
void ModelEntityRenderer::doRender(RenderArgs* args) {
DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender");
@ -1327,28 +1362,11 @@ void ModelEntityRenderer::doRender(RenderArgs* args) {
// Remap textures for the next frame to avoid flicker
// remapTextures();
#if 0
// update whether the model should be showing collision mesh (this may flag for fixupInScene)
bool showingCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS);
if (showingCollisionGeometry != _showCollisionGeometry) {
ShapeType type = _entity->getShapeType();
_showCollisionGeometry = showingCollisionGeometry;
if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) {
// NOTE: it is OK if _collisionMeshKey is nullptr
model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey);
// NOTE: the model will render the collisionGeometry if it has one
_model->setCollisionMesh(mesh);
} else {
// release mesh
if (_collisionMeshKey) {
collisionMeshCache.releaseMesh(_collisionMeshKey);
}
// clear model's collision geometry
model::MeshPointer mesh = nullptr;
_model->setCollisionMesh(mesh);
}
bool showCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS);
if (showCollisionGeometry != _showCollisionGeometry) {
_showCollisionGeometry = showCollisionGeometry;
flagForCollisionGeometryUpdate();
}
#endif
}
void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames) {

View file

@ -50,6 +50,8 @@ private:
};
class RenderableModelEntityItem : public ModelEntityWrapper {
Q_OBJECT
friend class render::entities::ModelEntityRenderer;
using Parent = ModelEntityWrapper;
public:
@ -105,6 +107,10 @@ public:
virtual QStringList getJointNames() const override;
bool getMeshes(MeshProxyList& result) override;
const void* getCollisionMeshKey() const { return _collisionMeshKey; }
signals:
void requestCollisionGeometryUpdate();
private:
bool needsUpdateModelBounds() const;
@ -117,7 +123,6 @@ private:
QVariantMap _originalTextures;
bool _dimensionsInitialized { true };
bool _needsJointSimulation { false };
bool _showCollisionGeometry { false };
const void* _collisionMeshKey { nullptr };
};
@ -141,6 +146,8 @@ protected:
virtual bool needsRenderUpdate() const override;
virtual void doRender(RenderArgs* args) override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
void flagForCollisionGeometryUpdate();
void setCollisionMeshKey(const void* key);
private:
void animate(const TypedEntityPointer& entity);
@ -163,6 +170,7 @@ private:
bool _needsJointSimulation{ false };
bool _showCollisionGeometry{ false };
bool _needsCollisionGeometryUpdate{ false };
const void* _collisionMeshKey{ nullptr };
// used on client side

View file

@ -69,8 +69,8 @@ ParticleEffectEntityRenderer::ParticleEffectEntityRenderer(const EntityItemPoint
}
bool ParticleEffectEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
entity->checkAndMaybeUpdateQueryAACube();
entity->updateQueryAACube();
if (_emitting != entity->getIsEmitting()) {
return true;
}

View file

@ -30,23 +30,6 @@ using namespace render::entities;
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
static const float SPHERE_ENTITY_SCALE = 0.5f;
static std::array<GeometryCache::Shape, entity::NUM_SHAPES> MAPPING { {
GeometryCache::Triangle,
GeometryCache::Quad,
GeometryCache::Hexagon,
GeometryCache::Octagon,
GeometryCache::Circle,
GeometryCache::Cube,
GeometryCache::Sphere,
GeometryCache::Tetrahedron,
GeometryCache::Octahedron,
GeometryCache::Dodecahedron,
GeometryCache::Icosahedron,
GeometryCache::Torus,
GeometryCache::Cone,
GeometryCache::Cylinder,
} };
ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
_procedural._vertexSource = simple_vert;
@ -137,11 +120,12 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch& batch = *args->_batch;
auto geometryCache = DependencyManager::get<GeometryCache>();
GeometryCache::Shape geometryShape;
bool proceduralRender = false;
glm::vec4 outColor;
withReadLock([&] {
geometryShape = MAPPING[_shape];
geometryShape = geometryCache->getShapeForEntityShape(_shape);
batch.setModelTransform(_renderTransform); // use a transform with scale, rotation, registration point and translation
outColor = _color;
if (_procedural.isReady()) {
@ -155,14 +139,13 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
if (proceduralRender) {
batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a);
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
DependencyManager::get<GeometryCache>()->renderWireShape(batch, geometryShape);
geometryCache->renderWireShape(batch, geometryShape);
} else {
DependencyManager::get<GeometryCache>()->renderShape(batch, geometryShape);
geometryCache->renderShape(batch, geometryShape);
}
} else {
// FIXME, support instanced multi-shape rendering using multidraw indirect
outColor.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
auto geometryCache = DependencyManager::get<GeometryCache>();
auto pipeline = outColor.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline();
if (render::ShapeKey(args->_globalShapeKey).isWireframe()) {
geometryCache->renderWireShapeInstance(args, batch, geometryShape, outColor, pipeline);
@ -171,6 +154,6 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
}
}
static const auto triCount = DependencyManager::get<GeometryCache>()->getShapeTriangleCount(geometryShape);
const auto triCount = geometryCache->getShapeTriangleCount(geometryShape);
args->_details._trianglesRendered += (int)triCount;
}

View file

@ -43,7 +43,7 @@ int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
EntityItem::EntityItem(const EntityItemID& entityItemID) :
SpatiallyNestable(NestableType::Entity, entityItemID)
SpatiallyNestable(NestableType::Entity, entityItemID)
{
setLocalVelocity(ENTITY_ITEM_DEFAULT_VELOCITY);
setLocalAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
@ -707,9 +707,17 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
}
}
auto lastEdited = lastEditedFromBufferAdjusted;
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) {
bool simulationChanged = lastEdited > updatedTimestamp;
return otherOverwrites && simulationChanged && (valueChanged || filterRejection);
};
{ // When we own the simulation we don't accept updates to the entity's transform/velocities
// we also want to ignore any duplicate packets that have the same "recently updated" values
// as a packet we've already recieved. This is because we want multiple edits of the same
// as a packet we've already recieved. This is because we want multiple edits of the same
// information to be idempotent, but if we applied new physics properties we'd resimulation
// with small differences in results.
@ -717,17 +725,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// made these lambdas that can access other details about the previous updates to suppress
// any duplicates.
// Note: duplicate packets are expected and not wrong. They may be sent for any number of
// Note: duplicate packets are expected and not wrong. They may be sent for any number of
// reasons and the contract is that the client handles them in an idempotent manner.
auto lastEdited = lastEditedFromBufferAdjusted;
bool otherOverwrites = overwriteLocalData && !weOwnSimulation;
auto shouldUpdate = [lastEdited, otherOverwrites, filterRejection](quint64 updatedTimestamp, bool valueChanged) {
bool simulationChanged = lastEdited > updatedTimestamp;
return otherOverwrites && simulationChanged && (valueChanged || filterRejection);
};
auto customUpdatePositionFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){
if (shouldUpdate(_lastUpdatedPositionTimestamp, value != _lastUpdatedPositionValue)) {
updatePositionFromNetwork(value);
updatePosition(value);
_lastUpdatedPositionTimestamp = lastEdited;
_lastUpdatedPositionValue = value;
}
@ -735,7 +737,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value){
if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) {
updateRotationFromNetwork(value);
updateRotation(value);
_lastUpdatedRotationTimestamp = lastEdited;
_lastUpdatedRotationValue = value;
}
@ -743,7 +745,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
auto customUpdateVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){
if (shouldUpdate(_lastUpdatedVelocityTimestamp, value != _lastUpdatedVelocityValue)) {
updateVelocityFromNetwork(value);
updateVelocity(value);
_lastUpdatedVelocityTimestamp = lastEdited;
_lastUpdatedVelocityValue = value;
}
@ -751,7 +753,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
auto customUpdateAngularVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){
if (shouldUpdate(_lastUpdatedAngularVelocityTimestamp, value != _lastUpdatedAngularVelocityValue)) {
updateAngularVelocityFromNetwork(value);
updateAngularVelocity(value);
_lastUpdatedAngularVelocityTimestamp = lastEdited;
_lastUpdatedAngularVelocityValue = value;
}
@ -770,8 +772,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, customUpdateVelocityFromNetwork);
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, customUpdateAngularVelocityFromNetwork);
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, customSetAcceleration);
}
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
@ -832,7 +832,18 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
overwriteLocalData = oldOverwrite;
}
READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, setQueryAACube);
{
auto customUpdateQueryAACubeFromNetwork = [this, shouldUpdate, lastEdited](AACube value){
if (shouldUpdate(_lastUpdatedQueryAACubeTimestamp, value != _lastUpdatedQueryAACubeValue)) {
setQueryAACube(value);
_lastUpdatedQueryAACubeTimestamp = lastEdited;
_lastUpdatedQueryAACubeValue = value;
}
};
READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, customUpdateQueryAACubeFromNetwork);
}
READ_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, QUuid, setLastEditedBy);
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
@ -1363,8 +1374,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lastEditedBy, setLastEditedBy);
AACube saveQueryAACube = _queryAACube;
if (checkAndMaybeUpdateQueryAACube() && saveQueryAACube != _queryAACube) {
if (updateQueryAACube()) {
somethingChanged = true;
}
@ -1528,6 +1538,9 @@ AACube EntityItem::getQueryAACube(bool& success) const {
return result;
}
bool EntityItem::shouldPuffQueryAACube() const {
return hasActions() || isChildOfMyAvatar() || isMovingRelativeToParent();
}
// NOTE: This should only be used in cases of old bitstreams which only contain radius data
// 0,0,0 --> maxDimension,maxDimension,maxDimension
@ -1641,7 +1654,7 @@ bool EntityItem::verifyStaticCertificateProperties() {
const auto hash = getStaticCertificateHash();
const auto text = reinterpret_cast<const unsigned char*>(hash.constData());
const unsigned int textLength = hash.length();
// After DEBUG_CERT ends, we will get/cache this once from the marketplace when needed, and it likely won't be RSA.
const char publicKey[] = "-----BEGIN PUBLIC KEY-----\n\
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALCoBiDAZOClO26tC5pd7JikBL61WIgp\n\
@ -1732,16 +1745,10 @@ void EntityItem::updateParentID(const QUuid& value) {
if (tree) {
tree->addToNeedsParentFixupList(getThisPointer());
}
updateQueryAACube();
}
}
void EntityItem::updatePositionFromNetwork(const glm::vec3& value) {
if (shouldSuppressLocationEdits()) {
return;
}
updatePosition(value);
}
void EntityItem::updateDimensions(const glm::vec3& value) {
if (getDimensions() != value) {
setDimensions(value);
@ -1764,13 +1771,6 @@ void EntityItem::updateRotation(const glm::quat& rotation) {
}
}
void EntityItem::updateRotationFromNetwork(const glm::quat& rotation) {
if (shouldSuppressLocationEdits()) {
return;
}
updateRotation(rotation);
}
void EntityItem::updateMass(float mass) {
// Setting the mass actually changes the _density (at fixed volume), however
// we must protect the density range to help maintain stability of physics simulation
@ -1821,13 +1821,6 @@ void EntityItem::updateVelocity(const glm::vec3& value) {
}
}
void EntityItem::updateVelocityFromNetwork(const glm::vec3& value) {
if (shouldSuppressLocationEdits()) {
return;
}
updateVelocity(value);
}
void EntityItem::updateDamping(float value) {
auto clampedDamping = glm::clamp(value, 0.0f, 1.0f);
if (_damping != clampedDamping) {
@ -1879,13 +1872,6 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) {
}
}
void EntityItem::updateAngularVelocityFromNetwork(const glm::vec3& value) {
if (shouldSuppressLocationEdits()) {
return;
}
updateAngularVelocity(value);
}
void EntityItem::updateAngularDamping(float value) {
auto clampedDamping = glm::clamp(value, 0.0f, 1.0f);
if (_angularDamping != clampedDamping) {
@ -1998,9 +1984,7 @@ void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask
// if this entity is a descendant of MyAvatar, don't collide with MyAvatar. This avoids the
// "bootstrapping" problem where you can shoot yourself across the room by grabbing something
// and holding it against your own avatar.
QUuid ancestorID = findAncestorOfType(NestableType::Avatar);
if (!ancestorID.isNull() &&
(ancestorID == Physics::getSessionUUID() || ancestorID == AVATAR_SELF_ID)) {
if (isChildOfMyAvatar()) {
iAmHoldingThis = true;
}
// also, don't bootstrap our own avatar with a hold action
@ -2107,6 +2091,7 @@ bool EntityItem::addAction(EntitySimulationPointer simulation, EntityDynamicPoin
removeActionInternal(action->getID());
}
});
updateQueryAACube();
return result;
}
@ -2165,6 +2150,8 @@ bool EntityItem::removeAction(EntitySimulationPointer simulation, const QUuid& a
checkWaitingToRemove(simulation);
success = removeActionInternal(actionID);
});
updateQueryAACube();
return success;
}
@ -2407,6 +2394,7 @@ QVariantMap EntityItem::getActionArguments(const QUuid& actionID) const {
}
bool EntityItem::shouldSuppressLocationEdits() const {
// if any of the actions indicate they'd like suppression, suppress
QHash<QUuid, EntityDynamicPointer>::const_iterator i = _objectActions.begin();
while (i != _objectActions.end()) {
if (i.value()->shouldSuppressLocationEdits()) {
@ -2415,6 +2403,11 @@ bool EntityItem::shouldSuppressLocationEdits() const {
i++;
}
// if any of the ancestors are MyAvatar, suppress
if (isChildOfMyAvatar()) {
return true;
}
return false;
}
@ -2477,16 +2470,16 @@ void EntityItem::globalizeProperties(EntityItemProperties& properties, const QSt
bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const {
// The intention for the query JSON filter and this method is to be flexible to handle a variety of filters for
// ALL entity properties. Some work will need to be done to the property system so that it can be more flexible
// (to grab the value and default value of a property given the string representation of that property, for example)
// currently the only property filter we handle is '+' for serverScripts
// which means that we only handle a filtered query asking for entities where the serverScripts property is non-default
static const QString SERVER_SCRIPTS_PROPERTY = "serverScripts";
foreach(const auto& property, jsonFilters.keys()) {
if (property == SERVER_SCRIPTS_PROPERTY && jsonFilters[property] == EntityQueryFilterSymbol::NonDefault) {
// check if this entity has a non-default value for serverScripts
@ -2497,7 +2490,7 @@ bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const {
}
}
}
// the json filter syntax did not match what we expected, return a match
return true;
}
@ -2510,7 +2503,7 @@ quint64 EntityItem::getLastSimulated() const {
return result;
}
void EntityItem::setLastSimulated(quint64 now) {
void EntityItem::setLastSimulated(quint64 now) {
withWriteLock([&] {
_lastSimulated = now;
});
@ -2531,7 +2524,7 @@ void EntityItem::setLastEdited(quint64 lastEdited) {
});
}
quint64 EntityItem::getLastBroadcast() const {
quint64 EntityItem::getLastBroadcast() const {
quint64 result;
withReadLock([&] {
result = _lastBroadcast;
@ -2539,19 +2532,19 @@ quint64 EntityItem::getLastBroadcast() const {
return result;
}
void EntityItem::setLastBroadcast(quint64 lastBroadcast) {
void EntityItem::setLastBroadcast(quint64 lastBroadcast) {
withWriteLock([&] {
_lastBroadcast = lastBroadcast;
});
}
void EntityItem::markAsChangedOnServer() {
void EntityItem::markAsChangedOnServer() {
withWriteLock([&] {
_changedOnServer = usecTimestampNow();
});
}
quint64 EntityItem::getLastChangedOnServer() const {
quint64 EntityItem::getLastChangedOnServer() const {
quint64 result;
withReadLock([&] {
result = _changedOnServer;
@ -2559,13 +2552,13 @@ quint64 EntityItem::getLastChangedOnServer() const {
return result;
}
void EntityItem::update(const quint64& now) {
void EntityItem::update(const quint64& now) {
withWriteLock([&] {
_lastUpdated = now;
_lastUpdated = now;
});
}
quint64 EntityItem::getLastUpdated() const {
quint64 EntityItem::getLastUpdated() const {
quint64 result;
withReadLock([&] {
result = _lastUpdated;
@ -2573,10 +2566,10 @@ quint64 EntityItem::getLastUpdated() const {
return result;
}
void EntityItem::requiresRecalcBoxes() {
void EntityItem::requiresRecalcBoxes() {
withWriteLock([&] {
_recalcAABox = true;
_recalcMinAACube = true;
_recalcAABox = true;
_recalcMinAACube = true;
_recalcMaxAACube = true;
});
}
@ -2589,7 +2582,7 @@ QString EntityItem::getHref() const {
return result;
}
QString EntityItem::getDescription() const {
QString EntityItem::getDescription() const {
QString result;
withReadLock([&] {
result = _description;
@ -2611,54 +2604,54 @@ float EntityItem::getLocalRenderAlpha() const {
return result;
}
void EntityItem::setLocalRenderAlpha(float localRenderAlpha) {
void EntityItem::setLocalRenderAlpha(float localRenderAlpha) {
withWriteLock([&] {
_localRenderAlpha = localRenderAlpha;
});
}
glm::vec3 EntityItem::getGravity() const {
glm::vec3 EntityItem::getGravity() const {
glm::vec3 result;
withReadLock([&] {
result = _gravity;
});
return result;
}
}
void EntityItem::setGravity(const glm::vec3& value) {
void EntityItem::setGravity(const glm::vec3& value) {
withWriteLock([&] {
_gravity = value;
});
}
glm::vec3 EntityItem::getAcceleration() const {
glm::vec3 EntityItem::getAcceleration() const {
glm::vec3 result;
withReadLock([&] {
result = _acceleration;
});
return result;
}
}
void EntityItem::setAcceleration(const glm::vec3& value) {
void EntityItem::setAcceleration(const glm::vec3& value) {
withWriteLock([&] {
_acceleration = value;
});
}
float EntityItem::getDamping() const {
float EntityItem::getDamping() const {
float result;
withReadLock([&] {
result = _damping;
});
return result;
}
void EntityItem::setDamping(float value) {
void EntityItem::setDamping(float value) {
withWriteLock([&] {
_damping = value;
});
}
float EntityItem::getRestitution() const {
float EntityItem::getRestitution() const {
float result;
withReadLock([&] {
result = _restitution;
@ -2666,7 +2659,7 @@ float EntityItem::getRestitution() const {
return result;
}
float EntityItem::getFriction() const {
float EntityItem::getFriction() const {
float result;
withReadLock([&] {
result = _friction;
@ -2675,35 +2668,35 @@ float EntityItem::getFriction() const {
}
// lifetime related properties.
float EntityItem::getLifetime() const {
float EntityItem::getLifetime() const {
float result;
withReadLock([&] {
result = _lifetime;
});
return result;
}
}
void EntityItem::setLifetime(float value) {
void EntityItem::setLifetime(float value) {
withWriteLock([&] {
_lifetime = value;
});
}
quint64 EntityItem::getCreated() const {
quint64 EntityItem::getCreated() const {
quint64 result;
withReadLock([&] {
result = _created;
});
return result;
}
}
void EntityItem::setCreated(quint64 value) {
void EntityItem::setCreated(quint64 value) {
withWriteLock([&] {
_created = value;
});
}
QString EntityItem::getScript() const {
QString EntityItem::getScript() const {
QString result;
withReadLock([&] {
result = _script;
@ -2711,13 +2704,13 @@ QString EntityItem::getScript() const {
return result;
}
void EntityItem::setScript(const QString& value) {
void EntityItem::setScript(const QString& value) {
withWriteLock([&] {
_script = value;
});
}
quint64 EntityItem::getScriptTimestamp() const {
quint64 EntityItem::getScriptTimestamp() const {
quint64 result;
withReadLock([&] {
result = _scriptTimestamp;
@ -2725,13 +2718,13 @@ quint64 EntityItem::getScriptTimestamp() const {
return result;
}
void EntityItem::setScriptTimestamp(const quint64 value) {
void EntityItem::setScriptTimestamp(const quint64 value) {
withWriteLock([&] {
_scriptTimestamp = value;
});
}
QString EntityItem::getServerScripts() const {
QString EntityItem::getServerScripts() const {
QString result;
withReadLock([&] {
result = _serverScripts;
@ -2741,12 +2734,12 @@ QString EntityItem::getServerScripts() const {
void EntityItem::setServerScripts(const QString& serverScripts) {
withWriteLock([&] {
_serverScripts = serverScripts;
_serverScripts = serverScripts;
_serverScriptsChangedTimestamp = usecTimestampNow();
});
}
QString EntityItem::getCollisionSoundURL() const {
QString EntityItem::getCollisionSoundURL() const {
QString result;
withReadLock([&] {
result = _collisionSoundURL;
@ -2754,22 +2747,22 @@ QString EntityItem::getCollisionSoundURL() const {
return result;
}
glm::vec3 EntityItem::getRegistrationPoint() const {
glm::vec3 EntityItem::getRegistrationPoint() const {
glm::vec3 result;
withReadLock([&] {
result = _registrationPoint;
});
return result;
}
}
void EntityItem::setRegistrationPoint(const glm::vec3& value) {
withWriteLock([&] {
_registrationPoint = glm::clamp(value, 0.0f, 1.0f);
_registrationPoint = glm::clamp(value, 0.0f, 1.0f);
});
dimensionsChanged(); // Registration Point affects the bounding box
}
float EntityItem::getAngularDamping() const {
float EntityItem::getAngularDamping() const {
float result;
withReadLock([&] {
result = _angularDamping;
@ -2777,13 +2770,13 @@ float EntityItem::getAngularDamping() const {
return result;
}
void EntityItem::setAngularDamping(float value) {
void EntityItem::setAngularDamping(float value) {
withWriteLock([&] {
_angularDamping = value;
});
}
QString EntityItem::getName() const {
QString EntityItem::getName() const {
QString result;
withReadLock([&] {
result = _name;
@ -2791,13 +2784,13 @@ QString EntityItem::getName() const {
return result;
}
void EntityItem::setName(const QString& value) {
void EntityItem::setName(const QString& value) {
withWriteLock([&] {
_name = value;
});
}
QString EntityItem::getDebugName() {
QString EntityItem::getDebugName() {
QString result = getName();
if (result.isEmpty()) {
result = getID().toString();
@ -2805,7 +2798,7 @@ QString EntityItem::getDebugName() {
return result;
}
bool EntityItem::getVisible() const {
bool EntityItem::getVisible() const {
bool result;
withReadLock([&] {
result = _visible;
@ -2813,13 +2806,18 @@ bool EntityItem::getVisible() const {
return result;
}
void EntityItem::setVisible(bool value) {
void EntityItem::setVisible(bool value) {
withWriteLock([&] {
_visible = value;
});
}
bool EntityItem::getCollisionless() const {
bool EntityItem::isChildOfMyAvatar() const {
QUuid ancestorID = findAncestorOfType(NestableType::Avatar);
return !ancestorID.isNull() && (ancestorID == Physics::getSessionUUID() || ancestorID == AVATAR_SELF_ID);
}
bool EntityItem::getCollisionless() const {
bool result;
withReadLock([&] {
result = _collisionless;
@ -2827,13 +2825,13 @@ bool EntityItem::getCollisionless() const {
return result;
}
void EntityItem::setCollisionless(bool value) {
void EntityItem::setCollisionless(bool value) {
withWriteLock([&] {
_collisionless = value;
});
}
uint8_t EntityItem::getCollisionMask() const {
uint8_t EntityItem::getCollisionMask() const {
uint8_t result;
withReadLock([&] {
result = _collisionMask;
@ -2841,13 +2839,13 @@ uint8_t EntityItem::getCollisionMask() const {
return result;
}
void EntityItem::setCollisionMask(uint8_t value) {
void EntityItem::setCollisionMask(uint8_t value) {
withWriteLock([&] {
_collisionMask = value;
});
}
bool EntityItem::getDynamic() const {
bool EntityItem::getDynamic() const {
if (SHAPE_TYPE_STATIC_MESH == getShapeType()) {
return false;
}
@ -2858,13 +2856,13 @@ bool EntityItem::getDynamic() const {
return result;
}
void EntityItem::setDynamic(bool value) {
void EntityItem::setDynamic(bool value) {
withWriteLock([&] {
_dynamic = value;
});
}
bool EntityItem::getLocked() const {
bool EntityItem::getLocked() const {
bool result;
withReadLock([&] {
result = _locked;
@ -2872,7 +2870,7 @@ bool EntityItem::getLocked() const {
return result;
}
void EntityItem::setLocked(bool value) {
void EntityItem::setLocked(bool value) {
withWriteLock([&] {
_locked = value;
});
@ -2895,7 +2893,7 @@ void EntityItem::updateLocked(bool value) {
}
}
QString EntityItem::getUserData() const {
QString EntityItem::getUserData() const {
QString result;
withReadLock([&] {
result = _userData;
@ -2903,7 +2901,7 @@ QString EntityItem::getUserData() const {
return result;
}
void EntityItem::setUserData(const QString& value) {
void EntityItem::setUserData(const QString& value) {
withWriteLock([&] {
_userData = value;
});
@ -2937,7 +2935,7 @@ DEFINE_PROPERTY_ACCESSOR(quint32, EditionNumber, editionNumber)
DEFINE_PROPERTY_ACCESSOR(quint32, EntityInstanceNumber, entityInstanceNumber)
DEFINE_PROPERTY_ACCESSOR(QString, CertificateID, certificateID)
uint32_t EntityItem::getDirtyFlags() const {
uint32_t EntityItem::getDirtyFlags() const {
uint32_t result;
withReadLock([&] {
result = _dirtyFlags;
@ -2952,7 +2950,7 @@ void EntityItem::markDirtyFlags(uint32_t mask) {
});
}
void EntityItem::clearDirtyFlags(uint32_t mask) {
void EntityItem::clearDirtyFlags(uint32_t mask) {
withWriteLock([&] {
_dirtyFlags &= ~mask;
});

View file

@ -240,6 +240,7 @@ public:
using SpatiallyNestable::getQueryAACube;
virtual AACube getQueryAACube(bool& success) const override;
virtual bool shouldPuffQueryAACube() const override;
QString getScript() const;
void setScript(const QString& value);
@ -273,6 +274,8 @@ public:
inline bool isVisible() const { return getVisible(); }
inline bool isInvisible() const { return !getVisible(); }
bool isChildOfMyAvatar() const;
bool getCollisionless() const;
void setCollisionless(bool value);
@ -354,20 +357,16 @@ public:
virtual void updateRegistrationPoint(const glm::vec3& value);
void updatePosition(const glm::vec3& value);
void updateParentID(const QUuid& value);
void updatePositionFromNetwork(const glm::vec3& value);
void updateDimensions(const glm::vec3& value);
void updateRotation(const glm::quat& rotation);
void updateRotationFromNetwork(const glm::quat& rotation);
void updateDensity(float value);
void updateMass(float value);
void updateVelocity(const glm::vec3& value);
void updateVelocityFromNetwork(const glm::vec3& value);
void updateDamping(float value);
void updateRestitution(float value);
void updateFriction(float value);
void updateGravity(const glm::vec3& value);
void updateAngularVelocity(const glm::vec3& value);
void updateAngularVelocityFromNetwork(const glm::vec3& value);
void updateAngularDamping(float value);
void updateCollisionless(bool value);
void updateCollisionMask(uint8_t value);
@ -629,12 +628,14 @@ protected:
glm::vec3 _lastUpdatedVelocityValue;
glm::vec3 _lastUpdatedAngularVelocityValue;
glm::vec3 _lastUpdatedAccelerationValue;
AACube _lastUpdatedQueryAACubeValue;
quint64 _lastUpdatedPositionTimestamp { 0 };
quint64 _lastUpdatedRotationTimestamp { 0 };
quint64 _lastUpdatedVelocityTimestamp { 0 };
quint64 _lastUpdatedAngularVelocityTimestamp { 0 };
quint64 _lastUpdatedAccelerationTimestamp { 0 };
quint64 _lastUpdatedQueryAACubeTimestamp { 0 };
};

View file

@ -84,28 +84,11 @@ void EntityItemProperties::setLastEdited(quint64 usecTime) {
_lastEdited = usecTime > _created ? usecTime : _created;
}
const char* shapeTypeNames[] = {
"none",
"box",
"sphere",
"capsule-x",
"capsule-y",
"capsule-z",
"cylinder-x",
"cylinder-y",
"cylinder-z",
"hull",
"plane",
"compound",
"simple-hull",
"simple-compound",
"static-mesh"
};
QHash<QString, ShapeType> stringToShapeTypeLookup;
void addShapeType(ShapeType type) {
stringToShapeTypeLookup[shapeTypeNames[type]] = type;
stringToShapeTypeLookup[ShapeInfo::getNameForShapeType(type)] = type;
}
void buildStringToShapeTypeLookup() {
@ -180,9 +163,7 @@ void EntityItemProperties::setCollisionMaskFromString(const QString& maskString)
}
QString EntityItemProperties::getShapeTypeAsString() const {
if (_shapeType < sizeof(shapeTypeNames) / sizeof(char *))
return QString(shapeTypeNames[_shapeType]);
return QString(shapeTypeNames[SHAPE_TYPE_NONE]);
return ShapeInfo::getNameForShapeType(_shapeType);
}
void EntityItemProperties::setShapeTypeFromString(const QString& shapeName) {

View file

@ -461,7 +461,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
// if they've changed.
entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
if (descendant->getNestableType() == NestableType::Entity) {
if (descendant->checkAndMaybeUpdateQueryAACube()) {
if (descendant->updateQueryAACube()) {
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
EntityItemProperties newQueryCubeProperties;
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
@ -1843,4 +1843,4 @@ QString EntityScriptingInterface::computeCertificateID(const QUuid& entityID) {
}
return result;
}
#endif
#endif

View file

@ -1029,7 +1029,8 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
changedProperties[index] = QString("queryAACube:") +
QString::number((int)center.x) + "," +
QString::number((int)center.y) + "," +
QString::number((int)center.z);
QString::number((int)center.z) + "/" +
QString::number(properties.getQueryAACube().getDimensions().x);
}
if (properties.positionChanged()) {
int index = changedProperties.indexOf("position");
@ -1807,7 +1808,7 @@ QVector<EntityItemID> EntityTree::sendEntities(EntityEditPacketSender* packetSen
addToNeedsParentFixupList(entity);
}
entity->forceQueryAACubeUpdate();
entity->checkAndMaybeUpdateQueryAACube();
entity->updateQueryAACube();
moveOperator.addEntityToMoveList(entity, entity->getQueryAACube());
i++;
} else {

View file

@ -51,6 +51,14 @@ namespace entity {
}
}
// shapeCalculator is a hook for external code that knows how to configure a ShapeInfo
// for given entity::Shape and dimensions
ShapeEntityItem::ShapeInfoCalculator shapeCalculator = nullptr;
void ShapeEntityItem::setShapeInfoCalulator(ShapeEntityItem::ShapeInfoCalculator callback) {
shapeCalculator = callback;
}
ShapeEntityItem::Pointer ShapeEntityItem::baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties) {
Pointer entity(new ShapeEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
entity->setProperties(properties);
@ -87,6 +95,7 @@ EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredP
}
void ShapeEntityItem::setShape(const entity::Shape& shape) {
const entity::Shape prevShape = _shape;
_shape = shape;
switch (_shape) {
case entity::Shape::Cube:
@ -99,6 +108,11 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) {
_type = EntityTypes::Shape;
break;
}
if (_shape != prevShape) {
// Internally grabs writeLock
markDirtyFlags(Simulation::DIRTY_SHAPE);
}
}
bool ShapeEntityItem::setProperties(const EntityItemProperties& properties) {
@ -219,6 +233,7 @@ void ShapeEntityItem::debugDump() const {
qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " name:" << _name;
qCDebug(entities) << " shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )";
qCDebug(entities) << " collisionShapeType:" << ShapeInfo::getNameForShapeType(getShapeType());
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
@ -233,73 +248,101 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) {
const glm::vec3 entityDimensions = getDimensions();
switch (_shape) {
case entity::Shape::Quad:
case entity::Shape::Cube:
{
_collisionShapeType = SHAPE_TYPE_BOX;
switch (_shape){
case entity::Shape::Quad: {
// Not in GeometryCache::buildShapes, unsupported.
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
//TODO WL21389: Add a SHAPE_TYPE_QUAD ShapeType and treat
// as a special box (later if desired support)
}
break;
case entity::Shape::Cube: {
_collisionShapeType = SHAPE_TYPE_BOX;
}
break;
case entity::Shape::Sphere: {
float diameter = entityDimensions.x;
const float MIN_DIAMETER = 0.001f;
const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
if (diameter > MIN_DIAMETER
&& fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR
&& fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) {
_collisionShapeType = SHAPE_TYPE_SPHERE;
} else {
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
}
break;
case entity::Shape::Sphere:
{
}
break;
case entity::Shape::Circle: {
_collisionShapeType = SHAPE_TYPE_CIRCLE;
}
break;
case entity::Shape::Cylinder: {
_collisionShapeType = SHAPE_TYPE_CYLINDER_Y;
// TODO WL21389: determine if rotation is axis-aligned
//const Transform::Quat & rot = _transform.getRotation();
float diameter = entityDimensions.x;
const float MIN_DIAMETER = 0.001f;
const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f;
if (diameter > MIN_DIAMETER
&& fabsf(diameter - entityDimensions.y) / diameter < MIN_RELATIVE_SPHERICAL_ERROR
&& fabsf(diameter - entityDimensions.z) / diameter < MIN_RELATIVE_SPHERICAL_ERROR) {
// TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and
// hull ( or dimensions, need circular cross section)
// Should allow for minor variance along axes?
_collisionShapeType = SHAPE_TYPE_SPHERE;
} else {
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
}
}
break;
case entity::Shape::Cone: {
if (shapeCalculator) {
shapeCalculator(this, info);
// shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL)
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
} else {
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
}
break;
case entity::Shape::Cylinder:
{
_collisionShapeType = SHAPE_TYPE_CYLINDER_Y;
// TODO WL21389: determine if rotation is axis-aligned
//const Transform::Quat & rot = _transform.getRotation();
// TODO WL21389: some way to tell apart SHAPE_TYPE_CYLINDER_Y, _X, _Z based on rotation and
// hull ( or dimensions, need circular cross section)
// Should allow for minor variance along axes?
}
break;
}
break;
// gons, ones, & angles built via GeometryCache::extrudePolygon
case entity::Shape::Triangle:
case entity::Shape::Hexagon:
case entity::Shape::Octagon:
case entity::Shape::Circle:
case entity::Shape::Octagon: {
if (shapeCalculator) {
shapeCalculator(this, info);
// shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL)
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
} else {
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
}
}
break;
// hedrons built via GeometryCache::setUpFlatShapes
case entity::Shape::Tetrahedron:
case entity::Shape::Octahedron:
case entity::Shape::Dodecahedron:
case entity::Shape::Icosahedron:
case entity::Shape::Cone:
{
//TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later)
case entity::Shape::Icosahedron: {
if ( shapeCalculator ) {
shapeCalculator(this, info);
// shapeCalculator only supports convex shapes (e.g. SHAPE_TYPE_HULL)
_collisionShapeType = SHAPE_TYPE_SIMPLE_HULL;
} else {
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
}
break;
case entity::Shape::Torus:
{
// Not in GeometryCache::buildShapes, unsupported.
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
//TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support)
}
break;
default:
{
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
}
break;
}
break;
case entity::Shape::Torus: {
// Not in GeometryCache::buildShapes, unsupported.
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
//TODO WL21389: SHAPE_TYPE_SIMPLE_HULL and pointCollection (later if desired support)
}
break;
default: {
_collisionShapeType = SHAPE_TYPE_ELLIPSOID;
}
break;
}
EntityItem::computeShapeInfo(info);
}
// This value specifes how the shape should be treated by physics calculations.
// This value specifies how the shape should be treated by physics calculations.
ShapeType ShapeEntityItem::getShapeType() const {
return _collisionShapeType;
}

View file

@ -34,7 +34,6 @@ namespace entity {
::QString stringFromShape(Shape shape);
}
class ShapeEntityItem : public EntityItem {
using Pointer = std::shared_ptr<ShapeEntityItem>;
static Pointer baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties);
@ -43,6 +42,9 @@ public:
static EntityItemPointer sphereFactory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties);
using ShapeInfoCalculator = std::function<void( const ShapeEntityItem * const shapeEntity, ShapeInfo& info)>;
static void setShapeInfoCalulator(ShapeInfoCalculator callback);
ShapeEntityItem(const EntityItemID& entityItemID);
void pureVirtualFunctionPlaceHolder() override { };

View file

@ -136,7 +136,7 @@ void SimpleEntitySimulation::sortEntitiesThatMoved() {
SetOfEntities::iterator itemItr = _entitiesToSort.begin();
while (itemItr != _entitiesToSort.end()) {
EntityItemPointer entity = *itemItr;
entity->checkAndMaybeUpdateQueryAACube();
entity->updateQueryAACube();
++itemItr;
}
EntitySimulation::sortEntitiesThatMoved();

View file

@ -0,0 +1,22 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// Draw texture 0 fetched at (1.0 - texcoord.x, texcoord.y)
//
// Created by Sam Gondelman on 10/24/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
uniform sampler2D colorMap;
in vec2 varTexCoord0;
out vec4 outFragColor;
void main(void) {
outFragColor = texture(colorMap, vec2(1.0 - varTexCoord0.x, varTexCoord0.y));
}

View file

@ -23,6 +23,7 @@ const char DrawNada_frag[] = "void main(void) {}"; // DrawNada is really simple.
#include "DrawWhite_frag.h"
#include "DrawTexture_frag.h"
#include "DrawTextureMirroredX_frag.h"
#include "DrawTextureOpaque_frag.h"
#include "DrawColoredTexture_frag.h"
@ -37,6 +38,7 @@ ShaderPointer StandardShaderLib::_drawTransformVertexPositionVS;
ShaderPointer StandardShaderLib::_drawNadaPS;
ShaderPointer StandardShaderLib::_drawWhitePS;
ShaderPointer StandardShaderLib::_drawTexturePS;
ShaderPointer StandardShaderLib::_drawTextureMirroredXPS;
ShaderPointer StandardShaderLib::_drawTextureOpaquePS;
ShaderPointer StandardShaderLib::_drawColoredTexturePS;
StandardShaderLib::ProgramMap StandardShaderLib::_programs;
@ -130,6 +132,13 @@ ShaderPointer StandardShaderLib::getDrawTexturePS() {
return _drawTexturePS;
}
ShaderPointer StandardShaderLib::getDrawTextureMirroredXPS() {
if (!_drawTextureMirroredXPS) {
_drawTextureMirroredXPS = gpu::Shader::createPixel(std::string(DrawTextureMirroredX_frag));
}
return _drawTextureMirroredXPS;
}
ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() {
if (!_drawTextureOpaquePS) {
_drawTextureOpaquePS = gpu::Shader::createPixel(std::string(DrawTextureOpaque_frag));

View file

@ -47,6 +47,7 @@ public:
static ShaderPointer getDrawWhitePS();
static ShaderPointer getDrawTexturePS();
static ShaderPointer getDrawTextureMirroredXPS();
static ShaderPointer getDrawTextureOpaquePS();
static ShaderPointer getDrawColoredTexturePS();
@ -67,6 +68,7 @@ protected:
static ShaderPointer _drawNadaPS;
static ShaderPointer _drawWhitePS;
static ShaderPointer _drawTexturePS;
static ShaderPointer _drawTextureMirroredXPS;
static ShaderPointer _drawTextureOpaquePS;
static ShaderPointer _drawColoredTexturePS;

View file

@ -491,6 +491,10 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {
return true;
}
if (_entity->shouldSuppressLocationEdits()) {
return false;
}
if (!isLocallyOwned()) {
// we don't own the simulation
@ -577,7 +581,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
}
if (properties.transformChanged()) {
if (_entity->checkAndMaybeUpdateQueryAACube()) {
if (_entity->updateQueryAACube()) {
// due to parenting, the server may not know where something is in world-space, so include the bounding cube.
properties.setQueryAACube(_entity->getQueryAACube());
}
@ -644,7 +648,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
_entity->forEachDescendant([&](SpatiallyNestablePointer descendant) {
if (descendant->getNestableType() == NestableType::Entity) {
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
if (descendant->checkAndMaybeUpdateQueryAACube()) {
if (descendant->updateQueryAACube()) {
EntityItemProperties newQueryCubeProperties;
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
newQueryCubeProperties.setLastEdited(properties.getLastEdited());

View file

@ -66,7 +66,7 @@ class PhysicsEngine;
class ObjectMotionState : public btMotionState {
public:
// These poroperties of the PhysicsEngine are "global" within the context of all ObjectMotionStates
// These properties of the PhysicsEngine are "global" within the context of all ObjectMotionStates
// (assuming just one PhysicsEngine). They are cached as statics for fast calculations in the
// ObjectMotionState context.
static void setWorldOffset(const glm::vec3& offset);

View file

@ -314,6 +314,7 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
shape = new btCylinderShapeZ(btHalfExtents);
}
break;
case SHAPE_TYPE_CIRCLE:
case SHAPE_TYPE_CYLINDER_Y: {
const glm::vec3 halfExtents = info.getHalfExtents();
const btVector3 btHalfExtents(halfExtents.x, halfExtents.y, halfExtents.z);

View file

@ -35,8 +35,8 @@ void DisplayPlugin::waitForPresent() {
}
}
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> DisplayPlugin::getHUDOperator() {
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> hudOperator;
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> DisplayPlugin::getHUDOperator() {
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> hudOperator;
{
QMutexLocker locker(&_presentMutex);
hudOperator = _hudOperator;

View file

@ -204,7 +204,7 @@ public:
void waitForPresent();
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator();
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> getHUDOperator();
static const QString& MENU_PATH();
@ -218,7 +218,7 @@ protected:
gpu::ContextPointer _gpuContext;
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> _hudOperator { std::function<void(gpu::Batch&, const gpu::TexturePointer&)>() };
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> _hudOperator { std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)>() };
private:
QMutex _presentMutex;

View file

@ -52,6 +52,46 @@
//#define WANT_DEBUG
// @note: Originally size entity::NUM_SHAPES
// As of Commit b93e91b9, render-utils no longer retains knowledge of
// entity lib, and thus doesn't know about entity::NUM_SHAPES. Should
// the enumerations be altered, this will need to be updated.
// @see ShapeEntityItem.h
static std::array<GeometryCache::Shape, (GeometryCache::NUM_SHAPES - 1)> MAPPING{ {
GeometryCache::Triangle,
GeometryCache::Quad,
GeometryCache::Hexagon,
GeometryCache::Octagon,
GeometryCache::Circle,
GeometryCache::Cube,
GeometryCache::Sphere,
GeometryCache::Tetrahedron,
GeometryCache::Octahedron,
GeometryCache::Dodecahedron,
GeometryCache::Icosahedron,
GeometryCache::Torus,
GeometryCache::Cone,
GeometryCache::Cylinder,
} };
static const std::array<const char * const, GeometryCache::NUM_SHAPES> GEOCACHE_SHAPE_STRINGS{ {
"Line",
"Triangle",
"Quad",
"Hexagon",
"Octagon",
"Circle",
"Cube",
"Sphere",
"Tetrahedron",
"Octahedron",
"Dodecahedron",
"Icosahedron",
"Torus",
"Cone",
"Cylinder"
} };
const int GeometryCache::UNKNOWN_ID = -1;
@ -69,6 +109,51 @@ static gpu::Stream::FormatPointer INSTANCED_SOLID_FADE_STREAM_FORMAT;
static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec3) * 2; // vertices and normals
static const uint SHAPE_NORMALS_OFFSET = sizeof(glm::vec3);
void GeometryCache::computeSimpleHullPointListForShape(const int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList) {
auto geometryCache = DependencyManager::get<GeometryCache>();
const GeometryCache::Shape geometryShape = GeometryCache::getShapeForEntityShape( entityShape );
const GeometryCache::ShapeData * shapeData = geometryCache->getShapeData( geometryShape );
if (!shapeData){
//--EARLY EXIT--( data isn't ready for some reason... )
return;
}
const gpu::BufferView & shapeVerts = shapeData->_positionView;
const gpu::BufferView::Size numItems = shapeVerts.getNumElements();
outPointList.reserve((int)numItems);
QVector<glm::vec3> uniqueVerts;
uniqueVerts.reserve((int)numItems);
const float MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED = 1.0e-6f; //< 1mm^2
for (gpu::BufferView::Index i = 0; i < (gpu::BufferView::Index)numItems; ++i) {
const int numUniquePoints = (int)uniqueVerts.size();
const geometry::Vec &curVert = shapeVerts.get<geometry::Vec>(i);
bool isUniquePoint = true;
for (int uniqueIndex = 0; uniqueIndex < numUniquePoints; ++uniqueIndex) {
const geometry::Vec knownVert = uniqueVerts[uniqueIndex];
const float distToKnownPoint = glm::length2(knownVert - curVert);
if (distToKnownPoint <= MAX_INCLUSIVE_FILTER_DISTANCE_SQUARED) {
isUniquePoint = false;
break;
}
}
if (!isUniquePoint) {
//--EARLY ITERATION EXIT--
continue;
}
uniqueVerts.push_back(curVert);
outPointList.push_back(curVert * entityExtents);
}
}
template <size_t SIDES>
std::vector<vec3> polygon() {
std::vector<vec3> result;
@ -85,7 +170,7 @@ void GeometryCache::ShapeData::setupVertices(gpu::BufferPointer& vertexBuffer, c
gpu::Buffer::Size offset = vertexBuffer->getSize();
vertexBuffer->append(vertices);
gpu::Buffer::Size viewSize = vertices.size() * 2 * sizeof(glm::vec3);
gpu::Buffer::Size viewSize = vertices.size() * sizeof(glm::vec3);
_positionView = gpu::BufferView(vertexBuffer, offset,
viewSize, SHAPE_VERTEX_STRIDE, POSITION_ELEMENT);
@ -441,12 +526,46 @@ void GeometryCache::buildShapes() {
extrudePolygon<64>(_shapes[Cone], _shapeVertices, _shapeIndices, true);
//Circle
drawCircle(_shapes[Circle], _shapeVertices, _shapeIndices);
// Not implememented yet:
// Not implemented yet:
//Quad,
//Torus,
}
const GeometryCache::ShapeData * GeometryCache::getShapeData(const Shape shape) const {
if (((int)shape < 0) || ((int)shape >= (int)_shapes.size())) {
qCWarning(renderutils) << "GeometryCache::getShapeData - Invalid shape " << shape << " specified. Returning default fallback.";
//--EARLY EXIT--( No valid shape data for shape )
return nullptr;
}
return &_shapes[shape];
}
GeometryCache::Shape GeometryCache::getShapeForEntityShape(int entityShape) {
if ((entityShape < 0) || (entityShape >= (int)MAPPING.size())) {
qCWarning(renderutils) << "GeometryCache::getShapeForEntityShape - Invalid shape " << entityShape << " specified. Returning default fallback.";
//--EARLY EXIT--( fall back to default assumption )
return GeometryCache::Sphere;
}
return MAPPING[entityShape];
}
QString GeometryCache::stringFromShape(GeometryCache::Shape geoShape)
{
if (((int)geoShape < 0) || ((int)geoShape >= (int)GeometryCache::NUM_SHAPES)) {
qCWarning(renderutils) << "GeometryCache::stringFromShape - Invalid shape " << geoShape << " specified.";
//--EARLY EXIT--
return "INVALID_GEOCACHE_SHAPE";
}
return GEOCACHE_SHAPE_STRINGS[geoShape];
}
gpu::Stream::FormatPointer& getSolidStreamFormat() {
if (!SOLID_STREAM_FORMAT) {
SOLID_STREAM_FORMAT = std::make_shared<gpu::Stream::Format>(); // 1 for everyone

View file

@ -147,6 +147,16 @@ public:
NUM_SHAPES,
};
/// @param entityShapeEnum: The entity::Shape enumeration for the shape
/// whose GeometryCache::Shape is desired.
/// @return GeometryCache::NUM_SHAPES in the event of an error; otherwise,
/// the GeometryCache::Shape enum which aligns with the
/// specified entityShapeEnum
static GeometryCache::Shape getShapeForEntityShape(int entityShapeEnum);
static QString stringFromShape(GeometryCache::Shape geoShape);
static void computeSimpleHullPointListForShape(int entityShape, const glm::vec3 &entityExtents, QVector<glm::vec3> &outPointList);
static uint8_t CUSTOM_PIPELINE_NUMBER;
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key);
static void registerShapePipeline() {
@ -355,15 +365,21 @@ public:
using VShape = std::array<ShapeData, NUM_SHAPES>;
VShape _shapes;
/// returns ShapeData associated with the specified shape,
/// otherwise nullptr in the event of an error.
const ShapeData * getShapeData(Shape shape) const;
private:
GeometryCache();
virtual ~GeometryCache();
void buildShapes();
typedef QPair<int, int> IntPair;
typedef QPair<unsigned int, unsigned int> VerticesIndices;
VShape _shapes;
gpu::PipelinePointer _standardDrawPipeline;
gpu::PipelinePointer _standardDrawPipelineNoBlend;

View file

@ -235,7 +235,6 @@ void Model::updateRenderItems() {
self->updateClusterMatrices();
Transform modelTransform = self->getTransform();
Transform physicsTransform = modelTransform;
modelTransform.setScale(glm::vec3(1.0f));
uint32_t deleteGeometryCounter = self->_deleteGeometryCounter;
@ -259,13 +258,12 @@ void Model::updateRenderItems() {
});
}
// collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset
Transform collisionMeshOffset;
collisionMeshOffset.setIdentity();
foreach(auto itemID, self->_collisionRenderItemsMap.keys()) {
transaction.updateItem<MeshPartPayload>(itemID, [physicsTransform, collisionMeshOffset](MeshPartPayload& data) {
transaction.updateItem<MeshPartPayload>(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) {
// update the model transform for this render item.
data.updateTransform(physicsTransform, collisionMeshOffset);
data.updateTransform(modelTransform, collisionMeshOffset);
});
}

View file

@ -441,7 +441,7 @@ void CompositeHUD::run(const RenderContextPointer& renderContext) {
// Grab the HUD texture
gpu::doInBatch(renderContext->args->_context, [&](gpu::Batch& batch) {
if (renderContext->args->_hudOperator) {
renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture);
renderContext->args->_hudOperator(batch, renderContext->args->_hudTexture, renderContext->args->_renderMode == RenderArgs::RenderMode::MIRROR_RENDER_MODE);
}
});
}

View file

@ -122,7 +122,7 @@ namespace render {
render::ScenePointer _scene;
int8_t _cameraMode { -1 };
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> _hudOperator;
std::function<void(gpu::Batch&, const gpu::TexturePointer&, bool mirror)> _hudOperator;
gpu::TexturePointer _hudTexture;
};

View file

@ -15,9 +15,38 @@
#include "NumericalConstants.h" // for MILLIMETERS_PER_METER
// Originally within EntityItemProperties.cpp
const char* shapeTypeNames[] = {
"none",
"box",
"sphere",
"capsule-x",
"capsule-y",
"capsule-z",
"cylinder-x",
"cylinder-y",
"cylinder-z",
"hull",
"plane",
"compound",
"simple-hull",
"simple-compound",
"static-mesh"
};
static const size_t SHAPETYPE_NAME_COUNT = (sizeof(shapeTypeNames) / sizeof((shapeTypeNames)[0]));
// Bullet doesn't support arbitrarily small shapes
const float MIN_HALF_EXTENT = 0.005f; // 0.5 cm
QString ShapeInfo::getNameForShapeType(ShapeType type) {
if (((int)type <= 0) || ((int)type >= (int)SHAPETYPE_NAME_COUNT)) {
type = (ShapeType)0;
}
return shapeTypeNames[(int)type];
}
void ShapeInfo::clear() {
_url.clear();
_pointCollection.clear();
@ -29,7 +58,6 @@ void ShapeInfo::clear() {
}
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) {
//TODO WL21389: Does this need additional cases and handling added?
_url = "";
_type = type;
setHalfExtents(halfExtents);
@ -38,6 +66,7 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
_halfExtents = glm::vec3(0.0f);
break;
case SHAPE_TYPE_BOX:
case SHAPE_TYPE_HULL:
break;
case SHAPE_TYPE_SPHERE: {
float radius = glm::length(halfExtents) / SQUARE_ROOT_OF_3;
@ -45,7 +74,13 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
_halfExtents = glm::vec3(radius);
}
break;
case SHAPE_TYPE_CIRCLE: {
_halfExtents = glm::vec3(_halfExtents.x, MIN_HALF_EXTENT, _halfExtents.z);
}
break;
case SHAPE_TYPE_COMPOUND:
case SHAPE_TYPE_SIMPLE_HULL:
case SHAPE_TYPE_SIMPLE_COMPOUND:
case SHAPE_TYPE_STATIC_MESH:
_url = QUrl(url);
break;
@ -56,9 +91,6 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
}
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
//TODO WL21389: Should this pointlist clearance added in case
// this is a re-purposed instance?
// See https://github.com/highfidelity/hifi/pull/11024#discussion_r128885491
_url = "";
_type = SHAPE_TYPE_BOX;
setHalfExtents(halfExtents);
@ -66,7 +98,6 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) {
}
void ShapeInfo::setSphere(float radius) {
//TODO WL21389: See comment in setBox regarding clearance
_url = "";
_type = SHAPE_TYPE_SPHERE;
radius = glm::max(radius, MIN_HALF_EXTENT);
@ -75,14 +106,11 @@ void ShapeInfo::setSphere(float radius) {
}
void ShapeInfo::setPointCollection(const ShapeInfo::PointCollection& pointCollection) {
//TODO WL21389: May need to skip resetting type here.
_pointCollection = pointCollection;
_type = (_pointCollection.size() > 0) ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
_doubleHashKey.clear();
}
void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
//TODO WL21389: See comment in setBox regarding clearance
_url = "";
_type = SHAPE_TYPE_CAPSULE_Y;
radius = glm::max(radius, MIN_HALF_EXTENT);
@ -123,8 +151,15 @@ int ShapeInfo::getLargestSubshapePointCount() const {
return numPoints;
}
float computeCylinderVolume(const float radius, const float height) {
return PI * radius * radius * 2.0f * height;
}
float computeCapsuleVolume(const float radius, const float cylinderHeight) {
return PI * radius * radius * (cylinderHeight + 4.0f * radius / 3.0f);
}
float ShapeInfo::computeVolume() const {
//TODO WL21389: Add support for other ShapeTypes( CYLINDER_X, CYLINDER_Y, etc).
const float DEFAULT_VOLUME = 1.0f;
float volume = DEFAULT_VOLUME;
switch(_type) {
@ -137,17 +172,37 @@ float ShapeInfo::computeVolume() const {
volume = 4.0f * PI * _halfExtents.x * _halfExtents.y * _halfExtents.z / 3.0f;
break;
}
case SHAPE_TYPE_CYLINDER_X: {
volume = computeCylinderVolume(_halfExtents.y, _halfExtents.x);
break;
}
case SHAPE_TYPE_CYLINDER_Y: {
float radius = _halfExtents.x;
volume = PI * radius * radius * 2.0f * _halfExtents.y;
volume = computeCylinderVolume(_halfExtents.x, _halfExtents.y);
break;
}
case SHAPE_TYPE_CYLINDER_Z: {
volume = computeCylinderVolume(_halfExtents.x, _halfExtents.z);
break;
}
case SHAPE_TYPE_CAPSULE_X: {
// Need to offset halfExtents.x by y to account for the system treating
// the x extent of the capsule as the cylindrical height + spherical radius.
const float cylinderHeight = 2.0f * (_halfExtents.x - _halfExtents.y);
volume = computeCapsuleVolume(_halfExtents.y, cylinderHeight);
break;
}
case SHAPE_TYPE_CAPSULE_Y: {
float radius = _halfExtents.x;
// Need to offset halfExtents.y by x to account for the system treating
// the y extent of the capsule as the cylindrical height + spherical radius.
float cylinderHeight = 2.0f * (_halfExtents.y - _halfExtents.x);
volume = PI * radius * radius * (cylinderHeight + 4.0f * radius / 3.0f);
const float cylinderHeight = 2.0f * (_halfExtents.y - _halfExtents.x);
volume = computeCapsuleVolume(_halfExtents.x, cylinderHeight);
break;
}
case SHAPE_TYPE_CAPSULE_Z: {
// Need to offset halfExtents.z by x to account for the system treating
// the z extent of the capsule as the cylindrical height + spherical radius.
const float cylinderHeight = 2.0f * (_halfExtents.z - _halfExtents.x);
volume = computeCapsuleVolume(_halfExtents.x, cylinderHeight);
break;
}
default:
@ -158,7 +213,6 @@ float ShapeInfo::computeVolume() const {
}
bool ShapeInfo::contains(const glm::vec3& point) const {
//TODO WL21389: Add support for other ShapeTypes like Ellipsoid/Compound.
switch(_type) {
case SHAPE_TYPE_SPHERE:
return glm::length(point) <= _halfExtents.x;
@ -203,7 +257,6 @@ bool ShapeInfo::contains(const glm::vec3& point) const {
}
const DoubleHashKey& ShapeInfo::getHash() const {
//TODO WL21389: Need to include the pointlist for SIMPLE_HULL in hash
// NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance.
if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) {
bool useOffset = glm::length2(_offset) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET;
@ -214,52 +267,103 @@ const DoubleHashKey& ShapeInfo::getHash() const {
uint32_t primeIndex = 0;
_doubleHashKey.computeHash((uint32_t)_type, primeIndex++);
// compute hash1
uint32_t hash = _doubleHashKey.getHash();
for (int j = 0; j < 3; ++j) {
// NOTE: 0.49f is used to bump the float up almost half a millimeter
// so the cast to int produces a round() effect rather than a floor()
hash ^= DoubleHashKey::hashFunction(
if (_type != SHAPE_TYPE_SIMPLE_HULL) {
// compute hash1
uint32_t hash = _doubleHashKey.getHash();
for (int j = 0; j < 3; ++j) {
// NOTE: 0.49f is used to bump the float up almost half a millimeter
// so the cast to int produces a round() effect rather than a floor()
hash ^= DoubleHashKey::hashFunction(
(uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f),
primeIndex++);
if (useOffset) {
hash ^= DoubleHashKey::hashFunction(
if (useOffset) {
hash ^= DoubleHashKey::hashFunction(
(uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f),
primeIndex++);
}
}
}
_doubleHashKey.setHash(hash);
_doubleHashKey.setHash(hash);
// compute hash2
hash = _doubleHashKey.getHash2();
for (int j = 0; j < 3; ++j) {
// NOTE: 0.49f is used to bump the float up almost half a millimeter
// so the cast to int produces a round() effect rather than a floor()
uint32_t floatHash = DoubleHashKey::hashFunction2(
// compute hash2
hash = _doubleHashKey.getHash2();
for (int j = 0; j < 3; ++j) {
// NOTE: 0.49f is used to bump the float up almost half a millimeter
// so the cast to int produces a round() effect rather than a floor()
uint32_t floatHash = DoubleHashKey::hashFunction2(
(uint32_t)(_halfExtents[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _halfExtents[j]) * 0.49f));
if (useOffset) {
floatHash ^= DoubleHashKey::hashFunction2(
if (useOffset) {
floatHash ^= DoubleHashKey::hashFunction2(
(uint32_t)(_offset[j] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[j]) * 0.49f));
}
hash += ~(floatHash << 17);
hash ^= (floatHash >> 11);
hash += (floatHash << 4);
hash ^= (floatHash >> 7);
hash += ~(floatHash << 10);
hash = (hash << 16) | (hash >> 16);
}
hash += ~(floatHash << 17);
hash ^= (floatHash >> 11);
hash += (floatHash << 4);
hash ^= (floatHash >> 7);
hash += ~(floatHash << 10);
hash = (hash << 16) | (hash >> 16);
}
_doubleHashKey.setHash2(hash);
_doubleHashKey.setHash2(hash);
} else {
if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_STATIC_MESH) {
QString url = _url.toString();
if (!url.isEmpty()) {
// fold the urlHash into both parts
QByteArray baUrl = url.toLocal8Bit();
const char *cUrl = baUrl.data();
uint32_t urlHash = qChecksum(cUrl, baUrl.count());
_doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash);
_doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash);
assert(_pointCollection.size() == (size_t)1);
const PointList & points = _pointCollection.back();
const int numPoints = (int)points.size();
uint32_t hash = _doubleHashKey.getHash();
uint32_t hash2 = _doubleHashKey.getHash2();
for (int pointIndex = 0; pointIndex < numPoints; ++pointIndex) {
// compute hash1 & 2
const glm::vec3 &curPoint = points[pointIndex];
for (int vecCompIndex = 0; vecCompIndex < 3; ++vecCompIndex) {
// NOTE: 0.49f is used to bump the float up almost half a millimeter
// so the cast to int produces a round() effect rather than a floor()
uint32_t valueToHash = (uint32_t)(curPoint[vecCompIndex] * MILLIMETERS_PER_METER + copysignf(1.0f, curPoint[vecCompIndex]) * 0.49f);
hash ^= DoubleHashKey::hashFunction(valueToHash, primeIndex++);
uint32_t floatHash = DoubleHashKey::hashFunction2(valueToHash);
if (useOffset) {
const uint32_t offsetValToHash = (uint32_t)(_offset[vecCompIndex] * MILLIMETERS_PER_METER + copysignf(1.0f, _offset[vecCompIndex])* 0.49f);
hash ^= DoubleHashKey::hashFunction(offsetValToHash, primeIndex++);
floatHash ^= DoubleHashKey::hashFunction2(offsetValToHash);
}
hash2 += ~(floatHash << 17);
hash2 ^= (floatHash >> 11);
hash2 += (floatHash << 4);
hash2 ^= (floatHash >> 7);
hash2 += ~(floatHash << 10);
hash2 = (hash2 << 16) | (hash2 >> 16);
}
}
_doubleHashKey.setHash(hash);
_doubleHashKey.setHash2(hash2);
}
QString url = _url.toString();
if (!url.isEmpty()) {
// fold the urlHash into both parts
QByteArray baUrl = url.toLocal8Bit();
uint32_t urlHash = qChecksum(baUrl.data(), baUrl.size());
_doubleHashKey.setHash(_doubleHashKey.getHash() ^ urlHash);
_doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ urlHash);
}
uint32_t numHulls = 0;
if (_type == SHAPE_TYPE_COMPOUND || _type == SHAPE_TYPE_SIMPLE_COMPOUND) {
numHulls = (uint32_t)_pointCollection.size();
} else if (_type == SHAPE_TYPE_SIMPLE_HULL) {
numHulls = 1;
}
if (numHulls > 0) {
uint32_t hash = DoubleHashKey::hashFunction(numHulls, primeIndex++);
_doubleHashKey.setHash(_doubleHashKey.getHash() ^ hash);
hash = DoubleHashKey::hashFunction2(numHulls);
_doubleHashKey.setHash2(_doubleHashKey.getHash2() ^ hash);
}
}
return _doubleHashKey;

View file

@ -46,7 +46,8 @@ enum ShapeType {
SHAPE_TYPE_SIMPLE_HULL,
SHAPE_TYPE_SIMPLE_COMPOUND,
SHAPE_TYPE_STATIC_MESH,
SHAPE_TYPE_ELLIPSOID
SHAPE_TYPE_ELLIPSOID,
SHAPE_TYPE_CIRCLE
};
class ShapeInfo {
@ -57,6 +58,8 @@ public:
using PointCollection = QVector<PointList>;
using TriangleIndices = QVector<int32_t>;
static QString getNameForShapeType(ShapeType type);
void clear();
void setParams(ShapeType type, const glm::vec3& halfExtents, QString url="");
@ -66,7 +69,7 @@ public:
void setCapsuleY(float radius, float halfHeight);
void setOffset(const glm::vec3& offset);
int getType() const { return _type; }
ShapeType getType() const { return _type; }
const glm::vec3& getHalfExtents() const { return _halfExtents; }
const glm::vec3& getOffset() const { return _offset; }

View file

@ -963,35 +963,41 @@ AACube SpatiallyNestable::getMaximumAACube(bool& success) const {
const float PARENTED_EXPANSION_FACTOR = 3.0f;
bool SpatiallyNestable::checkAndMaybeUpdateQueryAACube() {
bool success = false;
AACube maxAACube = getMaximumAACube(success);
if (success) {
// maybe update _queryAACube
if (!_queryAACubeSet || (_parentID.isNull() && _children.size() == 0) || !_queryAACube.contains(maxAACube)) {
if (_parentJointIndex != INVALID_JOINT_INDEX || _children.size() > 0 ) {
// make an expanded AACube centered on the object
float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale();
_queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale);
} else {
_queryAACube = maxAACube;
}
forEachDescendant([&](const SpatiallyNestablePointer& descendant) {
bool childSuccess;
AACube descendantAACube = descendant->getQueryAACube(childSuccess);
if (childSuccess) {
if (_queryAACube.contains(descendantAACube)) {
return ;
}
_queryAACube += descendantAACube.getMinimumPoint();
_queryAACube += descendantAACube.getMaximumPoint();
}
});
_queryAACubeSet = true;
}
bool SpatiallyNestable::updateQueryAACube() {
if (!queryAACubeNeedsUpdate()) {
return false;
}
return success;
bool success;
AACube maxAACube = getMaximumAACube(success);
if (!success) {
return false;
}
if (shouldPuffQueryAACube()) {
// make an expanded AACube centered on the object
float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale();
_queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale);
_queryAACubeIsPuffed = true;
} else {
_queryAACube = maxAACube;
_queryAACubeIsPuffed = false;
}
forEachDescendant([&](const SpatiallyNestablePointer& descendant) {
bool childSuccess;
AACube descendantAACube = descendant->getQueryAACube(childSuccess);
if (childSuccess) {
if (_queryAACube.contains(descendantAACube)) {
return; // from lambda
}
_queryAACube += descendantAACube.getMinimumPoint();
_queryAACube += descendantAACube.getMaximumPoint();
}
});
_queryAACubeSet = true;
return true;
}
void SpatiallyNestable::setQueryAACube(const AACube& queryAACube) {
@ -1008,6 +1014,16 @@ bool SpatiallyNestable::queryAACubeNeedsUpdate() const {
return true;
}
bool success;
AACube maxAACube = getMaximumAACube(success);
if (success && !_queryAACube.contains(maxAACube)) {
return true;
}
if (shouldPuffQueryAACube() != _queryAACubeIsPuffed) {
return true;
}
// make sure children are still in their boxes, also.
bool childNeedsUpdate = false;
forEachDescendantTest([&](const SpatiallyNestablePointer& descendant) {
@ -1021,31 +1037,6 @@ bool SpatiallyNestable::queryAACubeNeedsUpdate() const {
return childNeedsUpdate;
}
void SpatiallyNestable::updateQueryAACube() {
bool success;
AACube maxAACube = getMaximumAACube(success);
if (_parentJointIndex != INVALID_JOINT_INDEX || _children.size() > 0 ) {
// make an expanded AACube centered on the object
float scale = PARENTED_EXPANSION_FACTOR * maxAACube.getScale();
_queryAACube = AACube(maxAACube.calcCenter() - glm::vec3(0.5f * scale), scale);
} else {
_queryAACube = maxAACube;
}
forEachDescendant([&](const SpatiallyNestablePointer& descendant) {
bool success;
AACube descendantAACube = descendant->getQueryAACube(success);
if (success) {
if (_queryAACube.contains(descendantAACube)) {
return;
}
_queryAACube += descendantAACube.getMinimumPoint();
_queryAACube += descendantAACube.getMaximumPoint();
}
});
_queryAACubeSet = true;
}
AACube SpatiallyNestable::getQueryAACube(bool& success) const {
if (_queryAACubeSet) {
success = true;

View file

@ -106,11 +106,11 @@ public:
virtual glm::vec3 getParentAngularVelocity(bool& success) const;
virtual AACube getMaximumAACube(bool& success) const;
bool checkAndMaybeUpdateQueryAACube();
void updateQueryAACube();
virtual void setQueryAACube(const AACube& queryAACube);
virtual bool queryAACubeNeedsUpdate() const;
virtual bool shouldPuffQueryAACube() const { return false; }
bool updateQueryAACube();
void forceQueryAACubeUpdate() { _queryAACubeSet = false; }
virtual AACube getQueryAACube(bool& success) const;
virtual AACube getQueryAACube() const;
@ -234,6 +234,7 @@ private:
glm::vec3 _angularVelocity;
mutable bool _parentKnowsMe { false };
bool _isDead { false };
bool _queryAACubeIsPuffed { false };
};

View file

@ -104,8 +104,9 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersectionInternal(const glm::vec
if (_bounds.findRayIntersection(origin, direction, boxDistance, face, surfaceNormal)) {
// if our bounding box intersects at a distance greater than the current known
// best distance, than we can safely not check any of our triangles
if (boxDistance > bestDistance) {
// best distance, and our origin isn't inside the boounds, then we can safely
// not check any of our triangles
if (boxDistance > bestDistance && !_bounds.contains(origin)) {
return false;
}

View file

@ -1082,37 +1082,7 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid
}
}
static void forEachKeyboard(QQuickItem* parent, std::function<void(QQuickItem*)> function) {
if (!function) {
return;
}
auto keyboards = parent->findChildren<QObject*>("keyboard");
for (auto keyboardObject : keyboards) {
auto keyboard = qobject_cast<QQuickItem*>(keyboardObject);
if (keyboard) {
function(keyboard);
}
}
}
static const int TEXTINPUT_PASSWORD = 2;
static QQuickItem* getTopmostParent(QQuickItem* item) {
QObject* itemObject = item;
while (itemObject) {
if (itemObject->parent()) {
itemObject = itemObject->parent();
} else {
break;
}
}
return qobject_cast<QQuickItem*> (itemObject);
}
void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric) {
void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric, bool passwordField) {
#if Q_OS_ANDROID
return;
#endif
@ -1128,21 +1098,6 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n
return;
}
auto echoMode = item->property("echoMode");
bool isPasswordField = echoMode.isValid() && echoMode.toInt() == TEXTINPUT_PASSWORD;
// we need to somehow pass 'isPasswordField' to visible keyboard so it will change its 'mirror text' to asterixes
// the issue in some cases there might be more than one keyboard in object tree and it is hard to understand which one is being used at the moment
// unfortunately attempts to check for visibility failed becuase visibility is not updated yet. So... I don't see other way than just update properties for all the keyboards
auto topmostParent = getTopmostParent(item);
if (topmostParent) {
forEachKeyboard(topmostParent, [&](QQuickItem* keyboard) {
keyboard->setProperty("mirroredText", QVariant::fromValue(QString("")));
keyboard->setProperty("password", isPasswordField);
});
}
// for future probably makes sense to consider one of the following:
// 1. make keyboard a singleton, which will be dynamically re-parented before showing
// 2. track currently visible keyboard somewhere, allow to subscribe for this signal
@ -1153,15 +1108,15 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n
numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox";
if (item->property("keyboardRaised").isValid()) {
forEachKeyboard(item, [&](QQuickItem* keyboard) {
keyboard->setProperty("mirroredText", QVariant::fromValue(QString("")));
keyboard->setProperty("password", isPasswordField);
});
// FIXME - HMD only: Possibly set value of "keyboardEnabled" per isHMDMode() for use in WebView.qml.
if (item->property("punctuationMode").isValid()) {
item->setProperty("punctuationMode", QVariant(numeric));
}
if (item->property("passwordField").isValid()) {
item->setProperty("passwordField", QVariant(passwordField));
}
item->setProperty("keyboardRaised", QVariant(raised));
return;
}
@ -1186,9 +1141,13 @@ void OffscreenQmlSurface::emitWebEvent(const QVariant& message) {
const QString RAISE_KEYBOARD = "_RAISE_KEYBOARD";
const QString RAISE_KEYBOARD_NUMERIC = "_RAISE_KEYBOARD_NUMERIC";
const QString LOWER_KEYBOARD = "_LOWER_KEYBOARD";
const QString RAISE_KEYBOARD_NUMERIC_PASSWORD = "_RAISE_KEYBOARD_NUMERIC_PASSWORD";
const QString RAISE_KEYBOARD_PASSWORD = "_RAISE_KEYBOARD_PASSWORD";
QString messageString = message.type() == QVariant::String ? message.toString() : "";
if (messageString.left(RAISE_KEYBOARD.length()) == RAISE_KEYBOARD) {
setKeyboardRaised(_currentFocusItem, true, messageString == RAISE_KEYBOARD_NUMERIC);
bool numeric = (messageString == RAISE_KEYBOARD_NUMERIC || messageString == RAISE_KEYBOARD_NUMERIC_PASSWORD);
bool passwordField = (messageString == RAISE_KEYBOARD_PASSWORD || messageString == RAISE_KEYBOARD_NUMERIC_PASSWORD);
setKeyboardRaised(_currentFocusItem, true, numeric, passwordField);
} else if (messageString == LOWER_KEYBOARD) {
setKeyboardRaised(_currentFocusItem, false);
} else {

View file

@ -82,7 +82,7 @@ public:
QPointF mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget);
bool eventFilter(QObject* originalDestination, QEvent* event) override;
void setKeyboardRaised(QObject* object, bool raised, bool numeric = false);
void setKeyboardRaised(QObject* object, bool raised, bool numeric = false, bool passwordField = false);
Q_INVOKABLE void synthesizeKeyPress(QString key, QObject* targetOverride = nullptr);
using TextureAndFence = std::pair<uint32_t, void*>;

View file

@ -74,8 +74,8 @@
itemName: 'Test Flaregun',
itemPrice: (debugError ? 10 : 17),
itemHref: 'http://mpassets.highfidelity.com/0d90d21c-ce7a-4990-ad18-e9d2cf991027-v1/flaregun.json',
},
canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified
categories: ["Wearables", "Miscellaneous"]
}
});
}
}
@ -115,7 +115,6 @@
if (url === MARKETPLACE_PURCHASES_QML_PATH) {
tablet.sendToQml({
method: 'updatePurchases',
canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified,
referrerURL: referrerURL,
filterText: filterText
});
@ -136,9 +135,10 @@
function setCertificateInfo(currentEntityWithContextOverlay, itemCertificateId) {
wireEventBridge(true);
var certificateId = itemCertificateId || (Entities.getEntityProperties(currentEntityWithContextOverlay, ['certificateID']).certificateID + "\n");
tablet.sendToQml({
method: 'inspectionCertificate_setCertificateId',
certificateId: itemCertificateId || Entities.getEntityProperties(currentEntityWithContextOverlay, ['certificateID']).certificateID
certificateId: certificateId
});
}
@ -203,8 +203,7 @@
tablet.pushOntoStack(MARKETPLACE_CHECKOUT_QML_PATH);
tablet.sendToQml({
method: 'updateCheckoutQML',
params: parsedJsonMessage,
canRezCertifiedItems: Entities.canRezCertified || Entities.canRezTmpCertified
params: parsedJsonMessage
});
} else if (parsedJsonMessage.type === "REQUEST_SETTING") {
sendCommerceSettings();

View file

@ -10,18 +10,18 @@
gpu::Stream::FormatPointer& getInstancedSolidStreamFormat();
static const size_t TYPE_COUNT = 4;
static const size_t ITEM_COUNT = 50;
static const float SHAPE_INTERVAL = (PI * 2.0f) / ITEM_COUNT;
static const float ITEM_INTERVAL = SHAPE_INTERVAL / TYPE_COUNT;
static GeometryCache::Shape SHAPE[TYPE_COUNT] = {
static GeometryCache::Shape SHAPE[] = {
GeometryCache::Icosahedron,
GeometryCache::Cube,
GeometryCache::Sphere,
GeometryCache::Tetrahedron,
};
static const size_t TYPE_COUNT = (sizeof(SHAPE) / sizeof((SHAPE)[0]));
static const size_t ITEM_COUNT = 50;
static const float SHAPE_INTERVAL = (PI * 2.0f) / ITEM_COUNT;
static const float ITEM_INTERVAL = SHAPE_INTERVAL / TYPE_COUNT;
const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ };
const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA };
@ -34,8 +34,6 @@ TestInstancedShapes::TestInstancedShapes() {
static const float ITEM_RADIUS = 20;
static const vec3 ITEM_TRANSLATION { 0, 0, -ITEM_RADIUS };
for (size_t i = 0; i < TYPE_COUNT; ++i) {
GeometryCache::Shape shape = SHAPE[i];
GeometryCache::ShapeData shapeData = geometryCache->_shapes[shape];
//indirectCommand._count
float startingInterval = ITEM_INTERVAL * i;
std::vector<mat4> typeTransforms;
@ -62,7 +60,12 @@ void TestInstancedShapes::renderTest(size_t testId, RenderArgs* args) {
batch.setInputFormat(getInstancedSolidStreamFormat());
for (size_t i = 0; i < TYPE_COUNT; ++i) {
GeometryCache::Shape shape = SHAPE[i];
GeometryCache::ShapeData shapeData = geometryCache->_shapes[shape];
const GeometryCache::ShapeData *shapeData = geometryCache->getShapeData( shape );
if (!shapeData) {
//--EARLY ITERATION EXIT--( didn't have shape data yet )
continue;
}
std::string namedCall = __FUNCTION__ + std::to_string(i);
@ -71,13 +74,13 @@ void TestInstancedShapes::renderTest(size_t testId, RenderArgs* args) {
batch.setModelTransform(transforms[i][j]);
batch.setupNamedCalls(namedCall, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData&) {
batch.setInputBuffer(gpu::Stream::COLOR, gpu::BufferView(colorBuffer, i * ITEM_COUNT * 4, colorBuffer->getSize(), COLOR_ELEMENT));
shapeData.drawInstances(batch, ITEM_COUNT);
shapeData->drawInstances(batch, ITEM_COUNT);
});
}
//for (size_t j = 0; j < ITEM_COUNT; ++j) {
// batch.setModelTransform(transforms[j + i * ITEM_COUNT]);
// shapeData.draw(batch);
// shapeData->draw(batch);
//}
}
}