From ba9225438595b534bbd0262d1ee72565ea87f835 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 9 Mar 2015 13:31:54 -0700 Subject: [PATCH 01/26] Fix skeleton detection when uploading avatar model --- interface/src/ModelUploader.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index 9a56a75798..9310de53d4 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -179,21 +179,20 @@ bool ModelUploader::zip() { FBXGeometry geometry = readFBX(fbxContents, QVariantHash()); // Make sure that a skeleton model has a skeleton - if (_modelType == SKELETON_MODEL) { - if (geometry.rootJointIndex == -1) { - - QString message = "Your selected skeleton model has no skeleton.\n\nThe upload will be canceled."; - QMessageBox msgBox; - msgBox.setWindowTitle("Model Upload"); - msgBox.setText(message); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - - return false; - } - } + if (_modelType == SKELETON_MODEL && !geometry.getJointNames().contains("Hips")) { + qDebug() << QString("[Warning] %1 does not contain a skeleton.").arg(filename); + QString message = "Your selected skeleton model has no skeleton.\n\nThe upload will be canceled."; + QMessageBox msgBox; + msgBox.setWindowTitle("Model Upload"); + msgBox.setText(message); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setIcon(QMessageBox::Warning); + msgBox.exec(); + + return false; + } + // make sure we have some basic mappings populateBasicMapping(mapping, filename, geometry); From d25d3bc6abe25c9db6a9d90ec6dc0b99716e4bf8 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 9 Mar 2015 19:34:46 -0700 Subject: [PATCH 02/26] Get users online from Web API --- examples/users.js | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 examples/users.js diff --git a/examples/users.js b/examples/users.js new file mode 100644 index 0000000000..4b56fce505 --- /dev/null +++ b/examples/users.js @@ -0,0 +1,60 @@ +// +// users.js +// examples +// +// Created by David Rowe on 9 Mar 2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var usersWindow = (function () { + + var API_URL = "https://metaverse.highfidelity.io/api/v1/users?status=online", + HTTP_GET_TIMEOUT = 60000, // ms = 1 minute + usersRequest, + processUsers, + usersTimedOut, + usersTimer, + UPDATE_TIMEOUT = 1000; // ms = 1s + + function requestUsers() { + usersRequest = new XMLHttpRequest(); + usersRequest.open("GET", API_URL, true); + usersRequest.timeout = HTTP_GET_TIMEOUT * 1000; + usersRequest.ontimeout = usersTimedOut; + usersRequest.onreadystatechange = processUsers; + usersRequest.send(); + } + + processUsers = function () { + if (usersRequest.readyState === usersRequest.DONE) { + if (usersRequest.status === 200) { + // TODO: Process users data + } else { + print("Error: Request for users status returned " + usersRequest.status + " " + usersRequest.statusText); + } + + usersTimer = Script.setTimeout(requestUsers, UPDATE_TIMEOUT); // Update while after finished processing. + } + }; + + usersTimedOut = function () { + print("Error: Request for users status timed out"); + usersTimer = Script.setTimeout(requestUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay. + }; + + function setUp() { + + requestUsers(); + } + + function tearDown() { + Script.clearTimeout(usersTimer); + + } + + setUp(); + Script.scriptEnding.connect(tearDown); +}()); From 63d8da0233ad634fc908723601cfd692a988b8e0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 9 Mar 2015 22:29:24 -0700 Subject: [PATCH 03/26] Display user names in 2D window --- examples/users.js | 103 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 5 deletions(-) diff --git a/examples/users.js b/examples/users.js index 4b56fce505..1ee5a59115 100644 --- a/examples/users.js +++ b/examples/users.js @@ -11,13 +11,77 @@ var usersWindow = (function () { - var API_URL = "https://metaverse.highfidelity.io/api/v1/users?status=online", + var WINDOW_BOUNDS_2D = { x: 100, y: 100, width: 300, height: 200 }, + WINDOW_MARGIN_2D = 12, + WINDOW_FOREGROUND_COLOR_2D = { red: 240, green: 240, blue: 240 }, + WINDOW_FOREGROUND_ALPHA_2D = 0.9, + WINDOW_BACKGROUND_COLOR_2D = { red: 120, green: 120, blue: 120 }, + WINDOW_BACKGROUND_ALPHA_2D = 0.7, + usersPane2D, + USERS_PANE_TEXT_WIDTH_2D = WINDOW_BOUNDS_2D.width - 2 * WINDOW_MARGIN_2D, + USERS_FONT_2D = { size: 14 }, + USERNAME_SPACER = "\u00a0\u00a0\u00a0\u00a0", // Nonbreaking spaces + usernameSpacerWidth2D, + + usersOnline, + usersInLines = [], // 2D array of lines of users + + API_URL = "https://metaverse.highfidelity.io/api/v1/users?status=online", HTTP_GET_TIMEOUT = 60000, // ms = 1 minute usersRequest, processUsers, usersTimedOut, usersTimer, - UPDATE_TIMEOUT = 1000; // ms = 1s + UPDATE_TIMEOUT = 5000; // ms = 5s + + function updateWindow() { + var displayText = "", + numUsersDisplayed = 0, + lineText = "", + lineWidth = 0, + myUsername = GlobalServices.myUsername, + usernameWidth, + user, + i; + + usersInLines = []; + + for (i = 0; i < usersOnline.length; i += 1) { + user = usersOnline[i]; + if (user.username !== myUsername && user.online) { + usernameWidth = Overlays.textSize(usersPane2D, user.username).width; + + if (usersInLines.length === 0 || lineWidth + usernameSpacerWidth2D + usernameWidth > USERS_PANE_TEXT_WIDTH_2D) { + displayText += "\n" + lineText; + + // New line + usersInLines.push([i]); // New array in new line or userLines array + usersOnline[i].leftX = 0; // Augment usersOnline data + usersOnline[i].rightX = usernameWidth; + + lineText = user.username; + lineWidth = usernameWidth; + + } else { + // Append + usersInLines[usersInLines.length - 1].push(i); + + usersOnline[i].leftX = lineWidth + usernameSpacerWidth2D; + usersOnline[i].rightX = lineWidth + usernameSpacerWidth2D + usernameWidth; + + lineText += USERNAME_SPACER + user.username; + lineWidth = usersOnline[i].rightX; + } + + numUsersDisplayed += 1; + } + } + + displayText += "\n" + lineText; + displayText = displayText.slice(2); // Remove leading "\n"s. + + Overlays.editOverlay(usersPane2D, { text: numUsersDisplayed > 0 ? displayText : "No users online" }); + } function requestUsers() { usersRequest = new XMLHttpRequest(); @@ -29,14 +93,29 @@ var usersWindow = (function () { } processUsers = function () { + var response; + if (usersRequest.readyState === usersRequest.DONE) { if (usersRequest.status === 200) { - // TODO: Process users data + response = JSON.parse(usersRequest.responseText); + if (response.status !== "success") { + print("Error: Request for users status returned status = " + response.status); + usersTimer = Script.setTimeout(requestUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay. + return; + } + if (!response.hasOwnProperty("data") || !response.data.hasOwnProperty("users")) { + print("Error: Request for users status returned invalid data"); + usersTimer = Script.setTimeout(requestUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay. + return; + } + + usersOnline = response.data.users; + updateWindow(); } else { print("Error: Request for users status returned " + usersRequest.status + " " + usersRequest.statusText); } - usersTimer = Script.setTimeout(requestUsers, UPDATE_TIMEOUT); // Update while after finished processing. + usersTimer = Script.setTimeout(requestUsers, UPDATE_TIMEOUT); // Update after finished processing. } }; @@ -46,13 +125,27 @@ var usersWindow = (function () { }; function setUp() { + usersPane2D = Overlays.addOverlay("text", { + bounds: WINDOW_BOUNDS_2D, + topMargin: WINDOW_MARGIN_2D, + leftMargin: WINDOW_MARGIN_2D, + color: WINDOW_FOREGROUND_COLOR_2D, + alpha: WINDOW_FOREGROUND_ALPHA_2D, + backgroundColor: WINDOW_BACKGROUND_COLOR_2D, + backgroundAlpha: WINDOW_BACKGROUND_ALPHA_2D, + text: "", + font: USERS_FONT_2D, + visible: true + }); + + usernameSpacerWidth2D = Overlays.textSize(usersPane2D, USERNAME_SPACER).width; requestUsers(); } function tearDown() { Script.clearTimeout(usersTimer); - + Overlays.deleteOverlay(usersPane2D); } setUp(); From abb62fd8f974537dbd0e195d1852797ae749cb4d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 9 Mar 2015 22:29:54 -0700 Subject: [PATCH 04/26] Fix typo found in passing --- interface/src/ui/overlays/TextOverlay.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index 6387b42bc3..aea8487fd3 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -55,7 +55,7 @@ public: virtual TextOverlay* createClone() const; virtual QScriptValue getProperty(const QString& property); - QSizeF textSize(const QString& test) const; // Pixels + QSizeF textSize(const QString& text) const; // Pixels private: QString _text; From a4fe9c1a12e9a7d3983e129210d836d134fc47ed Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 10 Mar 2015 12:32:48 -0700 Subject: [PATCH 05/26] Click on username to TP to them --- examples/users.js | 70 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/examples/users.js b/examples/users.js index 1ee5a59115..edc9b0f28e 100644 --- a/examples/users.js +++ b/examples/users.js @@ -20,11 +20,13 @@ var usersWindow = (function () { usersPane2D, USERS_PANE_TEXT_WIDTH_2D = WINDOW_BOUNDS_2D.width - 2 * WINDOW_MARGIN_2D, USERS_FONT_2D = { size: 14 }, + usersLineHeight, + usersLineSpacing, USERNAME_SPACER = "\u00a0\u00a0\u00a0\u00a0", // Nonbreaking spaces usernameSpacerWidth2D, usersOnline, - usersInLines = [], // 2D array of lines of users + linesOfUserIndexes = [], // 2D array of lines of indexes into usersOnline API_URL = "https://metaverse.highfidelity.io/api/v1/users?status=online", HTTP_GET_TIMEOUT = 60000, // ms = 1 minute @@ -34,29 +36,75 @@ var usersWindow = (function () { usersTimer, UPDATE_TIMEOUT = 5000; // ms = 5s + function onMousePressEvent(event) { + var clickedOverlay, + numLinesBefore, + overlayX, + overlayY, + minY, + maxY, + lineClicked, + i, + userIndex, + foundUser; + + clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if (clickedOverlay === usersPane2D) { + overlayX = event.x - WINDOW_BOUNDS_2D.x - WINDOW_MARGIN_2D; + overlayY = event.y - WINDOW_BOUNDS_2D.y - WINDOW_MARGIN_2D; + + numLinesBefore = Math.floor(overlayY / (usersLineHeight + usersLineSpacing)); + minY = numLinesBefore * (usersLineHeight + usersLineSpacing); + maxY = minY + usersLineHeight; + + lineClicked = -1; + if (minY <= overlayY && overlayY <= maxY) { + lineClicked = numLinesBefore; + } + + if (0 <= lineClicked && lineClicked < linesOfUserIndexes.length) { + foundUser = false; + i = 0; + while (!foundUser && i < linesOfUserIndexes[lineClicked].length) { + userIndex = linesOfUserIndexes[lineClicked][i]; + foundUser = usersOnline[userIndex].leftX <= overlayX && overlayX <= usersOnline[userIndex].rightX; + i += 1; + } + + if (foundUser) { + location.goToUser(usersOnline[userIndex].username); + } + } + } + } + function updateWindow() { var displayText = "", numUsersDisplayed = 0, lineText = "", lineWidth = 0, - myUsername = GlobalServices.myUsername, + myUsername = GlobalServices.username, usernameWidth, user, i; - usersInLines = []; - + // Create 2D array of lines x IDs into usersOnline. + // Augment usersOnline entries with x-coordinates of left and right of displayed username. + linesOfUserIndexes = []; for (i = 0; i < usersOnline.length; i += 1) { user = usersOnline[i]; if (user.username !== myUsername && user.online) { + usernameWidth = Overlays.textSize(usersPane2D, user.username).width; - if (usersInLines.length === 0 || lineWidth + usernameSpacerWidth2D + usernameWidth > USERS_PANE_TEXT_WIDTH_2D) { + if (linesOfUserIndexes.length === 0 + || lineWidth + usernameSpacerWidth2D + usernameWidth > USERS_PANE_TEXT_WIDTH_2D) { + displayText += "\n" + lineText; // New line - usersInLines.push([i]); // New array in new line or userLines array - usersOnline[i].leftX = 0; // Augment usersOnline data + linesOfUserIndexes.push([i]); + usersOnline[i].leftX = 0; usersOnline[i].rightX = usernameWidth; lineText = user.username; @@ -64,8 +112,7 @@ var usersWindow = (function () { } else { // Append - usersInLines[usersInLines.length - 1].push(i); - + linesOfUserIndexes[linesOfUserIndexes.length - 1].push(i); usersOnline[i].leftX = lineWidth + usernameSpacerWidth2D; usersOnline[i].rightX = lineWidth + usernameSpacerWidth2D + usernameWidth; @@ -138,8 +185,13 @@ var usersWindow = (function () { visible: true }); + usersLineHeight = Math.floor(Overlays.textSize(usersPane2D, "1").height); + usersLineSpacing = Math.floor(Overlays.textSize(usersPane2D, "1\n2").height - 2 * usersLineHeight); + usernameSpacerWidth2D = Overlays.textSize(usersPane2D, USERNAME_SPACER).width; + Controller.mousePressEvent.connect(onMousePressEvent); + requestUsers(); } From 59762175e4f0e8b53ae8e28506b05d3305aa3a6f Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 10 Mar 2015 12:44:34 -0700 Subject: [PATCH 06/26] Grow/shrink window as size of users list changes --- examples/users.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/users.js b/examples/users.js index edc9b0f28e..03ded27c6a 100644 --- a/examples/users.js +++ b/examples/users.js @@ -11,7 +11,7 @@ var usersWindow = (function () { - var WINDOW_BOUNDS_2D = { x: 100, y: 100, width: 300, height: 200 }, + var WINDOW_BOUNDS_2D = { x: 100, y: 100, width: 300, height: 0 }, WINDOW_MARGIN_2D = 12, WINDOW_FOREGROUND_COLOR_2D = { red: 240, green: 240, blue: 240 }, WINDOW_FOREGROUND_ALPHA_2D = 0.9, @@ -127,7 +127,11 @@ var usersWindow = (function () { displayText += "\n" + lineText; displayText = displayText.slice(2); // Remove leading "\n"s. - Overlays.editOverlay(usersPane2D, { text: numUsersDisplayed > 0 ? displayText : "No users online" }); + Overlays.editOverlay(usersPane2D, { + text: numUsersDisplayed > 0 ? displayText : "No users online", + height: (numUsersDisplayed > 0 ? linesOfUserIndexes.length : 1) * (usersLineHeight + usersLineSpacing) + - usersLineSpacing + 2 * WINDOW_MARGIN_2D + }); } function requestUsers() { From 4e8fcd47c0857aa2c59552c3d7e2527260d3edc0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 10 Mar 2015 13:51:25 -0700 Subject: [PATCH 07/26] Show/hide users window with menu item --- examples/users.js | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/examples/users.js b/examples/users.js index 03ded27c6a..7004805996 100644 --- a/examples/users.js +++ b/examples/users.js @@ -33,9 +33,15 @@ var usersWindow = (function () { usersRequest, processUsers, usersTimedOut, - usersTimer, + usersTimer = null, UPDATE_TIMEOUT = 5000; // ms = 5s + MENU_NAME = "Tools", + MENU_ITEM = "Users Online", + MENI_ITEM_AFTER = "Chat...", + + isVisible = false; + function onMousePressEvent(event) { var clickedOverlay, numLinesBefore, @@ -48,6 +54,10 @@ var usersWindow = (function () { userIndex, foundUser; + if (!isVisible) { + return; + } + clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); if (clickedOverlay === usersPane2D) { overlayX = event.x - WINDOW_BOUNDS_2D.x - WINDOW_MARGIN_2D; @@ -175,6 +185,27 @@ var usersWindow = (function () { usersTimer = Script.setTimeout(requestUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay. }; + function setVisible(visible) { + isVisible = visible; + + if (isVisible) { + if (usersTimer === null) { + requestUsers(); + } + } else { + Script.clearTimeout(usersTimer); + usersTimer = null; + } + + Overlays.editOverlay(usersPane2D, { visible: isVisible }); + } + + function onMenuItemEvent(event) { + if (event === MENU_ITEM) { + setVisible(Menu.isOptionChecked(MENU_ITEM)); + } + } + function setUp() { usersPane2D = Overlays.addOverlay("text", { bounds: WINDOW_BOUNDS_2D, @@ -186,7 +217,7 @@ var usersWindow = (function () { backgroundAlpha: WINDOW_BACKGROUND_ALPHA_2D, text: "", font: USERS_FONT_2D, - visible: true + visible: isVisible }); usersLineHeight = Math.floor(Overlays.textSize(usersPane2D, "1").height); @@ -196,10 +227,21 @@ var usersWindow = (function () { Controller.mousePressEvent.connect(onMousePressEvent); + Menu.addMenuItem({ + menuName: MENU_NAME, + menuItemName: MENU_ITEM, + afterItem: MENI_ITEM_AFTER, + isCheckable: true, + isChecked: isVisible + }); + Menu.menuItemEvent.connect(onMenuItemEvent); + requestUsers(); } function tearDown() { + Menu.removeMenuItem(MENU_NAME, MENU_ITEM); + Script.clearTimeout(usersTimer); Overlays.deleteOverlay(usersPane2D); } From d071bc50a48437bfa6431d6567dc2e63c3e40878 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 10 Mar 2015 17:20:08 -0700 Subject: [PATCH 08/26] Change from paragraph of usernames to single column of usernames --- examples/users.js | 78 ++++++++++++----------------------------------- 1 file changed, 19 insertions(+), 59 deletions(-) diff --git a/examples/users.js b/examples/users.js index 7004805996..20693c220e 100644 --- a/examples/users.js +++ b/examples/users.js @@ -11,22 +11,21 @@ var usersWindow = (function () { - var WINDOW_BOUNDS_2D = { x: 100, y: 100, width: 300, height: 0 }, + var WINDOW_BOUNDS_2D = { x: 100, y: 100, width: 150, height: 0 }, WINDOW_MARGIN_2D = 12, WINDOW_FOREGROUND_COLOR_2D = { red: 240, green: 240, blue: 240 }, WINDOW_FOREGROUND_ALPHA_2D = 0.9, WINDOW_BACKGROUND_COLOR_2D = { red: 120, green: 120, blue: 120 }, WINDOW_BACKGROUND_ALPHA_2D = 0.7, usersPane2D, - USERS_PANE_TEXT_WIDTH_2D = WINDOW_BOUNDS_2D.width - 2 * WINDOW_MARGIN_2D, USERS_FONT_2D = { size: 14 }, usersLineHeight, usersLineSpacing, USERNAME_SPACER = "\u00a0\u00a0\u00a0\u00a0", // Nonbreaking spaces usernameSpacerWidth2D, - usersOnline, - linesOfUserIndexes = [], // 2D array of lines of indexes into usersOnline + usersOnline, // Raw data + linesOfUsers, // Array of indexes pointing into usersOnline API_URL = "https://metaverse.highfidelity.io/api/v1/users?status=online", HTTP_GET_TIMEOUT = 60000, // ms = 1 minute @@ -34,7 +33,7 @@ var usersWindow = (function () { processUsers, usersTimedOut, usersTimer = null, - UPDATE_TIMEOUT = 5000; // ms = 5s + UPDATE_TIMEOUT = 5000, // ms = 5s MENU_NAME = "Tools", MENU_ITEM = "Users Online", @@ -49,10 +48,7 @@ var usersWindow = (function () { overlayY, minY, maxY, - lineClicked, - i, - userIndex, - foundUser; + lineClicked; if (!isVisible) { return; @@ -72,74 +68,38 @@ var usersWindow = (function () { lineClicked = numLinesBefore; } - if (0 <= lineClicked && lineClicked < linesOfUserIndexes.length) { - foundUser = false; - i = 0; - while (!foundUser && i < linesOfUserIndexes[lineClicked].length) { - userIndex = linesOfUserIndexes[lineClicked][i]; - foundUser = usersOnline[userIndex].leftX <= overlayX && overlayX <= usersOnline[userIndex].rightX; - i += 1; - } + if (0 <= lineClicked && lineClicked < linesOfUsers.length + && overlayX <= usersOnline[linesOfUsers[lineClicked]].usernameWidth) { - if (foundUser) { - location.goToUser(usersOnline[userIndex].username); - } + print("Go to " + usersOnline[linesOfUsers[lineClicked]].username); + // DJRTODO + //location.goToUser(usersOnline[userIndex].username); } } } function updateWindow() { var displayText = "", - numUsersDisplayed = 0, - lineText = "", - lineWidth = 0, - myUsername = GlobalServices.username, - usernameWidth, + myUsername, user, i; - // Create 2D array of lines x IDs into usersOnline. - // Augment usersOnline entries with x-coordinates of left and right of displayed username. - linesOfUserIndexes = []; + myUsername = GlobalServices.username; + linesOfUsers = []; for (i = 0; i < usersOnline.length; i += 1) { user = usersOnline[i]; if (user.username !== myUsername && user.online) { - - usernameWidth = Overlays.textSize(usersPane2D, user.username).width; - - if (linesOfUserIndexes.length === 0 - || lineWidth + usernameSpacerWidth2D + usernameWidth > USERS_PANE_TEXT_WIDTH_2D) { - - displayText += "\n" + lineText; - - // New line - linesOfUserIndexes.push([i]); - usersOnline[i].leftX = 0; - usersOnline[i].rightX = usernameWidth; - - lineText = user.username; - lineWidth = usernameWidth; - - } else { - // Append - linesOfUserIndexes[linesOfUserIndexes.length - 1].push(i); - usersOnline[i].leftX = lineWidth + usernameSpacerWidth2D; - usersOnline[i].rightX = lineWidth + usernameSpacerWidth2D + usernameWidth; - - lineText += USERNAME_SPACER + user.username; - lineWidth = usersOnline[i].rightX; - } - - numUsersDisplayed += 1; + usersOnline[i].usernameWidth = Overlays.textSize(usersPane2D, user.username).width; + linesOfUsers.push(i); + displayText += "\n" + user.username; } } - displayText += "\n" + lineText; - displayText = displayText.slice(2); // Remove leading "\n"s. + displayText = displayText.slice(1); // Remove leading "\n". Overlays.editOverlay(usersPane2D, { - text: numUsersDisplayed > 0 ? displayText : "No users online", - height: (numUsersDisplayed > 0 ? linesOfUserIndexes.length : 1) * (usersLineHeight + usersLineSpacing) + text: linesOfUsers.length > 0 ? displayText : "No users online", + height: (linesOfUsers.length > 0 ? linesOfUsers.length : 1) * (usersLineHeight + usersLineSpacing) - usersLineSpacing + 2 * WINDOW_MARGIN_2D }); } From 3d11dde8ad44d867b1b926f822891b9630015951 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 10 Mar 2015 20:27:31 -0700 Subject: [PATCH 09/26] Check that the user configures a skeleton root joint Instead of just checking that the model has a "Hips" joint. --- interface/src/ModelUploader.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp index ad57fe21ad..a6b51aa938 100644 --- a/interface/src/ModelUploader.cpp +++ b/interface/src/ModelUploader.cpp @@ -178,11 +178,22 @@ bool ModelUploader::zip() { QByteArray fbxContents = fbx.readAll(); FBXGeometry geometry = readFBX(fbxContents, QVariantHash()); - // Make sure that a skeleton model has a skeleton - if (_modelType == SKELETON_MODEL && !geometry.getJointNames().contains("Hips")) { - qDebug() << QString("[Warning] %1 does not contain a skeleton.").arg(filename); + // make sure we have some basic mappings + populateBasicMapping(mapping, filename, geometry); + + // open the dialog to configure the rest + ModelPropertiesDialog properties(_modelType, mapping, basePath, geometry); + if (properties.exec() == QDialog::Rejected) { + return false; + } + mapping = properties.getMapping(); - QString message = "Your selected skeleton model has no skeleton.\n\nThe upload will be canceled."; + // Make sure that a mapping for the root joint has been specified + QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); + if (!joints.contains("jointRoot")) { + qDebug() << QString("[Warning] %1 root joint not configured for skeleton.").arg(filename); + + QString message = "Your did not configure a root joint for your skeleton model.\n\nThe upload will be canceled."; QMessageBox msgBox; msgBox.setWindowTitle("Model Upload"); msgBox.setText(message); @@ -193,16 +204,6 @@ bool ModelUploader::zip() { return false; } - // make sure we have some basic mappings - populateBasicMapping(mapping, filename, geometry); - - // open the dialog to configure the rest - ModelPropertiesDialog properties(_modelType, mapping, basePath, geometry); - if (properties.exec() == QDialog::Rejected) { - return false; - } - mapping = properties.getMapping(); - QByteArray nameField = mapping.value(NAME_FIELD).toByteArray(); QString urlBase; if (!nameField.isEmpty()) { From a3c4429e0beb6a2e8d4fe8ea04ac507cee24a1ce Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 09:36:26 -0700 Subject: [PATCH 10/26] Longer wait until requesting status again after request error --- examples/users.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/users.js b/examples/users.js index 20693c220e..c78f48df02 100644 --- a/examples/users.js +++ b/examples/users.js @@ -134,6 +134,8 @@ var usersWindow = (function () { updateWindow(); } else { print("Error: Request for users status returned " + usersRequest.status + " " + usersRequest.statusText); + usersTimer = Script.setTimeout(requestUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay. + return; } usersTimer = Script.setTimeout(requestUsers, UPDATE_TIMEOUT); // Update after finished processing. From ad08a7dde2734654d8fc706b37caf731ca4fc09d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 09:37:18 -0700 Subject: [PATCH 11/26] Position window at bottom left of screen --- examples/users.js | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/examples/users.js b/examples/users.js index c78f48df02..ee64514562 100644 --- a/examples/users.js +++ b/examples/users.js @@ -11,12 +11,13 @@ var usersWindow = (function () { - var WINDOW_BOUNDS_2D = { x: 100, y: 100, width: 150, height: 0 }, + var WINDOW_WIDTH_2D = 150, WINDOW_MARGIN_2D = 12, WINDOW_FOREGROUND_COLOR_2D = { red: 240, green: 240, blue: 240 }, WINDOW_FOREGROUND_ALPHA_2D = 0.9, WINDOW_BACKGROUND_COLOR_2D = { red: 120, green: 120, blue: 120 }, WINDOW_BACKGROUND_ALPHA_2D = 0.7, + windowHeight = 0, usersPane2D, USERS_FONT_2D = { size: 14 }, usersLineHeight, @@ -39,7 +40,9 @@ var usersWindow = (function () { MENU_ITEM = "Users Online", MENI_ITEM_AFTER = "Chat...", - isVisible = false; + isVisible = false, + + viewportHeight; function onMousePressEvent(event) { var clickedOverlay, @@ -56,8 +59,9 @@ var usersWindow = (function () { clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); if (clickedOverlay === usersPane2D) { - overlayX = event.x - WINDOW_BOUNDS_2D.x - WINDOW_MARGIN_2D; - overlayY = event.y - WINDOW_BOUNDS_2D.y - WINDOW_MARGIN_2D; + + overlayX = event.x - WINDOW_MARGIN_2D; + overlayY = event.y - viewportHeight + windowHeight - WINDOW_MARGIN_2D; numLinesBefore = Math.floor(overlayY / (usersLineHeight + usersLineSpacing)); minY = numLinesBefore * (usersLineHeight + usersLineSpacing); @@ -70,10 +74,8 @@ var usersWindow = (function () { if (0 <= lineClicked && lineClicked < linesOfUsers.length && overlayX <= usersOnline[linesOfUsers[lineClicked]].usernameWidth) { - - print("Go to " + usersOnline[linesOfUsers[lineClicked]].username); - // DJRTODO - //location.goToUser(usersOnline[userIndex].username); + //print("Go to " + usersOnline[linesOfUsers[lineClicked]].username); + location.goToUser(usersOnline[userIndex].username); } } } @@ -96,11 +98,13 @@ var usersWindow = (function () { } displayText = displayText.slice(1); // Remove leading "\n". + windowHeight = (linesOfUsers.length > 0 ? linesOfUsers.length : 1) * (usersLineHeight + usersLineSpacing) + - usersLineSpacing + 2 * WINDOW_MARGIN_2D; Overlays.editOverlay(usersPane2D, { - text: linesOfUsers.length > 0 ? displayText : "No users online", - height: (linesOfUsers.length > 0 ? linesOfUsers.length : 1) * (usersLineHeight + usersLineSpacing) - - usersLineSpacing + 2 * WINDOW_MARGIN_2D + y: viewportHeight - windowHeight, + height: windowHeight, + text: linesOfUsers.length > 0 ? displayText : "No users online" }); } @@ -168,9 +172,16 @@ var usersWindow = (function () { } } + function update() { + viewportHeight = Controller.getViewportDimensions().y; + Overlays.editOverlay(usersPane2D, { + y: viewportHeight - windowHeight + }); + } + function setUp() { usersPane2D = Overlays.addOverlay("text", { - bounds: WINDOW_BOUNDS_2D, + bounds: { x: 0, y: 0, width: WINDOW_WIDTH_2D, height: 0 }, topMargin: WINDOW_MARGIN_2D, leftMargin: WINDOW_MARGIN_2D, color: WINDOW_FOREGROUND_COLOR_2D, @@ -182,6 +193,7 @@ var usersWindow = (function () { visible: isVisible }); + viewportHeight = Controller.getViewportDimensions().y; usersLineHeight = Math.floor(Overlays.textSize(usersPane2D, "1").height); usersLineSpacing = Math.floor(Overlays.textSize(usersPane2D, "1\n2").height - 2 * usersLineHeight); @@ -198,6 +210,8 @@ var usersWindow = (function () { }); Menu.menuItemEvent.connect(onMenuItemEvent); + Script.update.connect(update); + requestUsers(); } From e4f7e35587c5f1a0aca057e802be8535790dfc9b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 11 Mar 2015 10:10:11 -0700 Subject: [PATCH 12/26] Hide edit tools when inactive --- examples/editEntities.js | 24 +++++++++++++++++------- examples/libraries/toolBars.js | 4 ++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/examples/editEntities.js b/examples/editEntities.js index 9568f4207f..faef875d9b 100644 --- a/examples/editEntities.js +++ b/examples/editEntities.js @@ -125,7 +125,7 @@ var toolBar = (function () { width: toolWidth, height: toolHeight, alpha: 0.9, - visible: true + visible: false }); browseModelsButton = toolBar.addTool({ @@ -133,7 +133,7 @@ var toolBar = (function () { width: toolWidth, height: toolHeight, alpha: 0.9, - visible: true + visible: false }); newCubeButton = toolBar.addTool({ @@ -142,7 +142,7 @@ var toolBar = (function () { width: toolWidth, height: toolHeight, alpha: 0.9, - visible: true + visible: false }); newSphereButton = toolBar.addTool({ @@ -151,7 +151,7 @@ var toolBar = (function () { width: toolWidth, height: toolHeight, alpha: 0.9, - visible: true + visible: false }); newLightButton = toolBar.addTool({ @@ -160,7 +160,7 @@ var toolBar = (function () { width: toolWidth, height: toolHeight, alpha: 0.9, - visible: true + visible: false }); newTextButton = toolBar.addTool({ @@ -169,9 +169,8 @@ var toolBar = (function () { width: toolWidth, height: toolHeight, alpha: 0.9, - visible: true + visible: false }); - } that.setActive = function(active) { @@ -196,11 +195,22 @@ var toolBar = (function () { propertiesTool.setVisible(true); Window.setFocus(); } + that.showTools(isActive); } } toolBar.selectTool(activeButton, isActive); }; + // Sets visibility of tool buttons, excluding the power button + that.showTools = function(doShow) { + toolBar.showTool(newModelButton, doShow); + toolBar.showTool(browseModelsButton, doShow); + toolBar.showTool(newCubeButton, doShow); + toolBar.showTool(newSphereButton, doShow); + toolBar.showTool(newLightButton, doShow); + toolBar.showTool(newTextButton, doShow); + }; + var RESIZE_INTERVAL = 50; var RESIZE_TIMEOUT = 120000; // 2 minutes var RESIZE_MAX_CHECKS = RESIZE_TIMEOUT / RESIZE_INTERVAL; diff --git a/examples/libraries/toolBars.js b/examples/libraries/toolBars.js index 5802625d7b..951b6704ec 100644 --- a/examples/libraries/toolBars.js +++ b/examples/libraries/toolBars.js @@ -271,6 +271,10 @@ ToolBar = function(x, y, direction) { }); } } + + this.showTool = function(tool, doShow) { + this.tools[tool].show(doShow); + } this.show = function(doShow) { for(var tool in this.tools) { From c30bf5667ff03f8b1833a2d9eb1834977f969fa4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 10:15:34 -0700 Subject: [PATCH 13/26] Fix teleporting to user --- examples/users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/users.js b/examples/users.js index ee64514562..5f6d9e0854 100644 --- a/examples/users.js +++ b/examples/users.js @@ -75,7 +75,7 @@ var usersWindow = (function () { if (0 <= lineClicked && lineClicked < linesOfUsers.length && overlayX <= usersOnline[linesOfUsers[lineClicked]].usernameWidth) { //print("Go to " + usersOnline[linesOfUsers[lineClicked]].username); - location.goToUser(usersOnline[userIndex].username); + location.goToUser(usersOnline[linesOfUsers[lineClicked]].username); } } } From d36399c65d845c8355e811b85a47859e2df0531d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 10:21:49 -0700 Subject: [PATCH 14/26] Add heading --- examples/users.js | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/examples/users.js b/examples/users.js index 5f6d9e0854..2340039618 100644 --- a/examples/users.js +++ b/examples/users.js @@ -15,10 +15,13 @@ var usersWindow = (function () { WINDOW_MARGIN_2D = 12, WINDOW_FOREGROUND_COLOR_2D = { red: 240, green: 240, blue: 240 }, WINDOW_FOREGROUND_ALPHA_2D = 0.9, - WINDOW_BACKGROUND_COLOR_2D = { red: 120, green: 120, blue: 120 }, + WINDOW_HEADING_COLOR_2D = { red: 180, green: 180, blue: 180 }, + WINDOW_HEADING_ALPHA_2D = 0.9, + WINDOW_BACKGROUND_COLOR_2D = { red: 80, green: 80, blue: 80 }, WINDOW_BACKGROUND_ALPHA_2D = 0.7, windowHeight = 0, usersPane2D, + usersHeading2D, USERS_FONT_2D = { size: 14 }, usersLineHeight, usersLineSpacing, @@ -61,7 +64,7 @@ var usersWindow = (function () { if (clickedOverlay === usersPane2D) { overlayX = event.x - WINDOW_MARGIN_2D; - overlayY = event.y - viewportHeight + windowHeight - WINDOW_MARGIN_2D; + overlayY = event.y - viewportHeight + windowHeight - WINDOW_MARGIN_2D - (usersLineHeight + usersLineSpacing); numLinesBefore = Math.floor(overlayY / (usersLineHeight + usersLineSpacing)); minY = numLinesBefore * (usersLineHeight + usersLineSpacing); @@ -97,14 +100,18 @@ var usersWindow = (function () { } } - displayText = displayText.slice(1); // Remove leading "\n". - windowHeight = (linesOfUsers.length > 0 ? linesOfUsers.length : 1) * (usersLineHeight + usersLineSpacing) - - usersLineSpacing + 2 * WINDOW_MARGIN_2D; + windowHeight = (linesOfUsers.length > 0 ? linesOfUsers.length + 1 : 1) * (usersLineHeight + usersLineSpacing) + - usersLineSpacing + 2 * WINDOW_MARGIN_2D; // First or only line is for heading Overlays.editOverlay(usersPane2D, { y: viewportHeight - windowHeight, height: windowHeight, - text: linesOfUsers.length > 0 ? displayText : "No users online" + text: displayText + }); + + Overlays.editOverlay(usersHeading2D, { + y: viewportHeight - windowHeight + WINDOW_MARGIN_2D, + text: linesOfUsers.length > 0 ? "Online" : "No users online" }); } @@ -164,6 +171,7 @@ var usersWindow = (function () { } Overlays.editOverlay(usersPane2D, { visible: isVisible }); + Overlays.editOverlay(usersHeading2D, { visible: isVisible }); } function onMenuItemEvent(event) { @@ -177,6 +185,9 @@ var usersWindow = (function () { Overlays.editOverlay(usersPane2D, { y: viewportHeight - windowHeight }); + Overlays.editOverlay(usersHeading2D, { + y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + }) } function setUp() { @@ -193,6 +204,20 @@ var usersWindow = (function () { visible: isVisible }); + usersHeading2D = Overlays.addOverlay("text", { + x: WINDOW_MARGIN_2D, + width: WINDOW_WIDTH_2D - 2 * WINDOW_MARGIN_2D, + height: USERS_FONT_2D.size, + topMargin: 0, + leftMargin: 0, + color: WINDOW_HEADING_COLOR_2D, + alpha: WINDOW_HEADING_ALPHA_2D, + backgroundAlpha: 0.0, + text: "No users online", + font: USERS_FONT_2D, + visible: isVisible + }); + viewportHeight = Controller.getViewportDimensions().y; usersLineHeight = Math.floor(Overlays.textSize(usersPane2D, "1").height); usersLineSpacing = Math.floor(Overlays.textSize(usersPane2D, "1\n2").height - 2 * usersLineHeight); @@ -219,6 +244,7 @@ var usersWindow = (function () { Menu.removeMenuItem(MENU_NAME, MENU_ITEM); Script.clearTimeout(usersTimer); + Overlays.deleteOverlay(usersHeading2D); Overlays.deleteOverlay(usersPane2D); } From 22ff97fd276d8c9c41bf96606af605627e5aebb0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 10:25:24 -0700 Subject: [PATCH 15/26] Make visible by default --- examples/users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/users.js b/examples/users.js index 2340039618..8919ab08b4 100644 --- a/examples/users.js +++ b/examples/users.js @@ -43,7 +43,7 @@ var usersWindow = (function () { MENU_ITEM = "Users Online", MENI_ITEM_AFTER = "Chat...", - isVisible = false, + isVisible = true, viewportHeight; From 6c978c0ff3a77da165203e2b58330b2260c493c9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 11 Mar 2015 10:27:38 -0700 Subject: [PATCH 16/26] Add look.js Merges both lookWithMouse and lookWithTouch, and updates mouse look to only work with right-click --- examples/look.js | 168 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 examples/look.js diff --git a/examples/look.js b/examples/look.js new file mode 100644 index 0000000000..bcdfcf9e44 --- /dev/null +++ b/examples/look.js @@ -0,0 +1,168 @@ +// +// look.js +// examples +// +// Copyright 2015 High Fidelity, Inc. +// +// This is an example script that demonstrates use of the Controller class +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var wantDebugging = false; + + +// Configuration +var TOUCH_YAW_SCALE = -0.25; +var TOUCH_PITCH_SCALE = -12.5; +var FIXED_TOUCH_TIMESTEP = 0.016; + +var MOUSE_YAW_SCALE = -0.25; +var MOUSE_PITCH_SCALE = -12.5; +var FIXED_MOUSE_TIMESTEP = 0.016; + +// Mouse Data +var alwaysLook = false; // if you want the mouse look to happen only when you click, change this to false +var isMouseDown = false; +var lastTouchX = 0; +var lastTouchY = 0; +var yawFromTouch = 0; +var pitchFromTouch = 0; + +// Touch Data +var startedTouching = false; +var lastMouseX = 0; +var lastMouseY = 0; +var yawFromMouse = 0; +var pitchFromMouse = 0; + + +// Mouse Events +function mousePressEvent(event) { + if (wantDebugging) { + print("mousePressEvent event.x,y=" + event.x + ", " + event.y); + } + if (event.isRightButton) { + isMouseDown = true; + lastMouseX = event.x; + lastMouseY = event.y; + } +} + +function mouseReleaseEvent(event) { + if (wantDebugging) { + print("mouseReleaseEvent event.x,y=" + event.x + ", " + event.y); + } + isMouseDown = false; +} + +function mouseMoveEvent(event) { + if (wantDebugging) { + print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y); + } + + if (alwaysLook || isMouseDown) { + yawFromMouse += ((event.x - lastMouseX) * MOUSE_YAW_SCALE * FIXED_MOUSE_TIMESTEP); + pitchFromMouse += ((event.y - lastMouseY) * MOUSE_PITCH_SCALE * FIXED_MOUSE_TIMESTEP); + lastMouseX = event.x; + lastMouseY = event.y; + } +} + +// Touch Events +function touchBeginEvent(event) { + if (wantDebugging) { + print("touchBeginEvent event.x,y=" + event.x + ", " + event.y); + } + lastTouchX = event.x; + lastTouchY = event.y; + yawFromTouch = 0; + pitchFromTouch = 0; + startedTouching = true; + print("TOUCH BEGIN"); +} + +function touchEndEvent(event) { + if (wantDebugging) { + print("touchEndEvent event.x,y=" + event.x + ", " + event.y); + } + startedTouching = false; + print("TOUCH END"); +} + +function touchUpdateEvent(event) { + // print("TOUCH UPDATE"); + if (wantDebugging) { + print("touchUpdateEvent event.x,y=" + event.x + ", " + event.y); + } + + if (!startedTouching) { + // handle Qt 5.4.x bug where we get touch update without a touch begin event + startedTouching = true; + lastTouchX = event.x; + lastTouchY = event.y; + } + + yawFromTouch += ((event.x - lastTouchX) * TOUCH_YAW_SCALE * FIXED_TOUCH_TIMESTEP); + pitchFromTouch += ((event.y - lastTouchY) * TOUCH_PITCH_SCALE * FIXED_TOUCH_TIMESTEP); + lastTouchX = event.x; + lastTouchY = event.y; +} + + +function update(deltaTime) { + if (wantDebugging) { + print("update()..."); + } + + if (yawFromTouch != 0 || yawFromMouse != 0) { + var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollRadians(0, yawFromTouch + yawFromMouse, 0)); + + if (wantDebugging) { + print("changing orientation" + + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," + + MyAvatar.orientation.z + "," + MyAvatar.orientation.w + + " newOrientation="+newOrientation.x + "," + newOrientation.y + "," + newOrientation.z + "," + newOrientation.w); + } + + MyAvatar.orientation = newOrientation; + yawFromTouch = 0; + yawFromMouse = 0; + } + + if (pitchFromTouch != 0 || pitchFromMouse != 0) { + var newPitch = MyAvatar.headPitch + pitchFromTouch + pitchFromMouse; + + if (wantDebugging) { + print("changing pitch [old]MyAvatar.headPitch="+MyAvatar.headPitch+ " newPitch="+newPitch); + } + + MyAvatar.headPitch = newPitch; + pitchFromTouch = 0; + pitchFromMouse = 0; + } +} + + +// Map the mouse events to our functions +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseMoveEvent.connect(mouseMoveEvent); +Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + +// Map the mouse events to our functions +Controller.touchBeginEvent.connect(touchBeginEvent); +Controller.touchUpdateEvent.connect(touchUpdateEvent); +Controller.touchEndEvent.connect(touchEndEvent); + +// disable the standard application for mouse events +Controller.captureTouchEvents(); + +function scriptEnding() { + // re-enabled the standard application for mouse events + Controller.releaseTouchEvents(); +} + +// would be nice to change to update +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); From 532e4feebb627fa7a8646e26604c8bd6ad21d84d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 10:30:09 -0700 Subject: [PATCH 17/26] Remove dead code and fix typos --- examples/users.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/users.js b/examples/users.js index 8919ab08b4..e40c3878ce 100644 --- a/examples/users.js +++ b/examples/users.js @@ -25,8 +25,6 @@ var usersWindow = (function () { USERS_FONT_2D = { size: 14 }, usersLineHeight, usersLineSpacing, - USERNAME_SPACER = "\u00a0\u00a0\u00a0\u00a0", // Nonbreaking spaces - usernameSpacerWidth2D, usersOnline, // Raw data linesOfUsers, // Array of indexes pointing into usersOnline @@ -187,7 +185,7 @@ var usersWindow = (function () { }); Overlays.editOverlay(usersHeading2D, { y: viewportHeight - windowHeight + WINDOW_MARGIN_2D - }) + }); } function setUp() { @@ -219,11 +217,10 @@ var usersWindow = (function () { }); viewportHeight = Controller.getViewportDimensions().y; + usersLineHeight = Math.floor(Overlays.textSize(usersPane2D, "1").height); usersLineSpacing = Math.floor(Overlays.textSize(usersPane2D, "1\n2").height - 2 * usersLineHeight); - usernameSpacerWidth2D = Overlays.textSize(usersPane2D, USERNAME_SPACER).width; - Controller.mousePressEvent.connect(onMousePressEvent); Menu.addMenuItem({ From bbffa6474bc5a777eaf3e132c04912023a37404b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 10:32:14 -0700 Subject: [PATCH 18/26] Add users.js to default scripts --- examples/defaultScripts.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index 65682deb74..d4efad9ee5 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -17,4 +17,5 @@ Script.load("headMove.js"); Script.load("inspect.js"); Script.load("lobby.js"); Script.load("notifications.js"); -Script.load("lookWithMouse.js") +Script.load("lookWithMouse.js"); +Script.load("users.js"); From 1a18decc6d003f4e224897afe17511eabf83bb6b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 10:49:36 -0700 Subject: [PATCH 19/26] Fix typo --- examples/users.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/users.js b/examples/users.js index e40c3878ce..e2b0e7f053 100644 --- a/examples/users.js +++ b/examples/users.js @@ -39,7 +39,7 @@ var usersWindow = (function () { MENU_NAME = "Tools", MENU_ITEM = "Users Online", - MENI_ITEM_AFTER = "Chat...", + MENU_ITEM_AFTER = "Chat...", isVisible = true, @@ -226,7 +226,7 @@ var usersWindow = (function () { Menu.addMenuItem({ menuName: MENU_NAME, menuItemName: MENU_ITEM, - afterItem: MENI_ITEM_AFTER, + afterItem: MENU_ITEM_AFTER, isCheckable: true, isChecked: isVisible }); From fd423e5019c72745ec756da0a0d9975875133744 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 11:07:02 -0700 Subject: [PATCH 20/26] Fix units --- examples/users.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/users.js b/examples/users.js index e2b0e7f053..0274cd7321 100644 --- a/examples/users.js +++ b/examples/users.js @@ -116,7 +116,7 @@ var usersWindow = (function () { function requestUsers() { usersRequest = new XMLHttpRequest(); usersRequest.open("GET", API_URL, true); - usersRequest.timeout = HTTP_GET_TIMEOUT * 1000; + usersRequest.timeout = HTTP_GET_TIMEOUT; usersRequest.ontimeout = usersTimedOut; usersRequest.onreadystatechange = processUsers; usersRequest.send(); From 32897de80a93bda247f86ada24dfbc8cab9ab860 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 11 Mar 2015 12:41:47 -0700 Subject: [PATCH 21/26] Rename Stereo Audio menu item --- interface/src/Menu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3166e1fa37..1f29cfd175 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -248,7 +248,7 @@ namespace MenuOption { const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations"; const QString Stars = "Stars"; const QString Stats = "Stats"; - const QString StereoAudio = "Stereo Audio"; + const QString StereoAudio = "Stereo Audio (disables spatial sound)"; const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString TestPing = "Test Ping"; From feafa0a60b3f583616e21f30a6e622d9f4a9c35d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 11 Mar 2015 14:29:03 -0700 Subject: [PATCH 22/26] remove old Ragdoll and avatar interactions --- interface/src/Menu.cpp | 9 - interface/src/Menu.h | 4 - interface/src/avatar/Avatar.cpp | 11 - interface/src/avatar/Avatar.h | 9 - interface/src/avatar/MuscleConstraint.cpp | 33 - interface/src/avatar/MuscleConstraint.h | 43 -- interface/src/avatar/MyAvatar.cpp | 451 +---------- interface/src/avatar/MyAvatar.h | 13 - interface/src/avatar/SkeletonModel.cpp | 232 +----- interface/src/avatar/SkeletonModel.h | 17 - interface/src/avatar/SkeletonRagdoll.cpp | 145 ---- interface/src/avatar/SkeletonRagdoll.h | 43 -- libraries/avatars/src/AvatarData.cpp | 5 - libraries/avatars/src/AvatarData.h | 4 +- libraries/physics/src/ContactConstraint.cpp | 53 -- libraries/physics/src/ContactConstraint.h | 39 - libraries/physics/src/ContactPoint.cpp | 216 ------ libraries/physics/src/ContactPoint.h | 55 -- libraries/physics/src/DistanceConstraint.cpp | 44 -- libraries/physics/src/DistanceConstraint.h | 31 - libraries/physics/src/FixedConstraint.cpp | 35 - libraries/physics/src/FixedConstraint.h | 36 - libraries/physics/src/PhysicsEntity.cpp | 32 +- libraries/physics/src/PhysicsEntity.h | 14 - libraries/physics/src/PhysicsSimulation.cpp | 405 ---------- libraries/physics/src/PhysicsSimulation.h | 92 --- libraries/physics/src/Ragdoll.cpp | 146 ---- libraries/physics/src/Ragdoll.h | 91 --- libraries/physics/src/VerletCapsuleShape.cpp | 170 ---- libraries/physics/src/VerletCapsuleShape.h | 84 -- libraries/physics/src/VerletPoint.cpp | 54 -- libraries/physics/src/VerletPoint.h | 42 - libraries/physics/src/VerletSphereShape.cpp | 54 -- libraries/physics/src/VerletSphereShape.h | 49 -- libraries/shared/src/Shape.h | 3 - tests/physics/src/VerletShapeTests.cpp | 766 ------------------- tests/physics/src/VerletShapeTests.h | 30 - tests/physics/src/main.cpp | 2 - 38 files changed, 14 insertions(+), 3548 deletions(-) delete mode 100644 interface/src/avatar/MuscleConstraint.cpp delete mode 100644 interface/src/avatar/MuscleConstraint.h delete mode 100644 interface/src/avatar/SkeletonRagdoll.cpp delete mode 100644 interface/src/avatar/SkeletonRagdoll.h delete mode 100644 libraries/physics/src/ContactConstraint.cpp delete mode 100644 libraries/physics/src/ContactConstraint.h delete mode 100644 libraries/physics/src/ContactPoint.cpp delete mode 100644 libraries/physics/src/ContactPoint.h delete mode 100644 libraries/physics/src/DistanceConstraint.cpp delete mode 100644 libraries/physics/src/DistanceConstraint.h delete mode 100644 libraries/physics/src/FixedConstraint.cpp delete mode 100644 libraries/physics/src/FixedConstraint.h delete mode 100644 libraries/physics/src/PhysicsSimulation.cpp delete mode 100644 libraries/physics/src/PhysicsSimulation.h delete mode 100644 libraries/physics/src/Ragdoll.cpp delete mode 100644 libraries/physics/src/Ragdoll.h delete mode 100644 libraries/physics/src/VerletCapsuleShape.cpp delete mode 100644 libraries/physics/src/VerletCapsuleShape.h delete mode 100644 libraries/physics/src/VerletPoint.cpp delete mode 100644 libraries/physics/src/VerletPoint.h delete mode 100644 libraries/physics/src/VerletSphereShape.cpp delete mode 100644 libraries/physics/src/VerletSphereShape.h delete mode 100644 tests/physics/src/VerletShapeTests.cpp delete mode 100644 tests/physics/src/VerletShapeTests.h diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ea63b9879f..ad03062a89 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -205,7 +205,6 @@ Menu::Menu() { Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehavior())); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ScriptedMotorControl, 0, true, avatar, SLOT(updateMotionBehavior())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ChatCircling, 0, false); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); @@ -216,14 +215,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false, avatar, SLOT(updateMotionBehavior())); - QMenu* collisionsMenu = avatarMenu->addMenu("Collide With"); - addCheckableActionToQMenuAndActionHash(collisionsMenu, MenuOption::CollideAsRagdoll, 0, false, - avatar, SLOT(onToggleRagdoll())); - addCheckableActionToQMenuAndActionHash(collisionsMenu, MenuOption::CollideWithAvatars, - 0, true, avatar, SLOT(updateCollisionGroups())); - addCheckableActionToQMenuAndActionHash(collisionsMenu, MenuOption::CollideWithEnvironment, - 0, false, avatar, SLOT(updateCollisionGroups())); - QMenu* viewMenu = addMenu("View"); #ifdef Q_OS_MAC diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3166e1fa37..721cf8d9cf 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -127,10 +127,6 @@ namespace MenuOption { const QString CascadedShadows = "Cascaded"; const QString CachesSize = "RAM Caches Size"; const QString Chat = "Chat..."; - const QString ChatCircling = "Chat Circling"; - const QString CollideAsRagdoll = "Collide With Self (Ragdoll)"; - const QString CollideWithAvatars = "Collide With Other Avatars"; - const QString CollideWithEnvironment = "Collide With World Boundaries"; const QString Collisions = "Collisions"; const QString Console = "Console..."; const QString ControlWithSpeech = "Control With Speech"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 3333c0ab92..a0fa21c674 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -74,7 +74,6 @@ Avatar::Avatar() : _scale(1.0f), _worldUpDirection(DEFAULT_UP_DIRECTION), _moving(false), - _collisionGroups(0), _initialized(false), _shouldRenderBillboard(true), _voiceSphereID(GeometryCache::UNKNOWN_ID) @@ -999,16 +998,6 @@ void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, } } -void Avatar::updateCollisionGroups() { - _collisionGroups = 0; - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideWithEnvironment)) { - _collisionGroups |= COLLISION_GROUP_ENVIRONMENT; - } - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideWithAvatars)) { - _collisionGroups |= COLLISION_GROUP_AVATARS; - } -} - void Avatar::setScale(float scale) { _scale = scale; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 2951208d95..e9a21af98e 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -59,7 +59,6 @@ class Texture; class Avatar : public AvatarData { Q_OBJECT - Q_PROPERTY(quint32 collisionGroups READ getCollisionGroups WRITE setCollisionGroups) Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset) public: @@ -137,9 +136,6 @@ public: /// \return bounding radius of avatar virtual float getBoundingRadius() const; - quint32 getCollisionGroups() const { return _collisionGroups; } - virtual void setCollisionGroups(quint32 collisionGroups) { _collisionGroups = (collisionGroups & VALID_COLLISION_GROUPS); } - Q_INVOKABLE void setSkeletonOffset(const glm::vec3& offset); Q_INVOKABLE glm::vec3 getSkeletonOffset() { return _skeletonOffset; } virtual glm::vec3 getSkeletonPosition() const; @@ -171,9 +167,6 @@ public: // (otherwise floating point error will cause problems at large positions). void applyPositionDelta(const glm::vec3& delta); -public slots: - void updateCollisionGroups(); - signals: void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision); @@ -203,8 +196,6 @@ protected: float _stringLength; bool _moving; ///< set when position is changing - quint32 _collisionGroups; - // protected methods... glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } diff --git a/interface/src/avatar/MuscleConstraint.cpp b/interface/src/avatar/MuscleConstraint.cpp deleted file mode 100644 index 76f30fdbc4..0000000000 --- a/interface/src/avatar/MuscleConstraint.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// -// MuscleConstraint.cpp -// interface/src/avatar -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include - -#include "MuscleConstraint.h" - -const float DEFAULT_MUSCLE_STRENGTH = 0.5f * MAX_MUSCLE_STRENGTH; - -MuscleConstraint::MuscleConstraint(VerletPoint* parent, VerletPoint* child) : _rootPoint(parent), _childPoint(child), - _parentIndex(-1), _childndex(-1), _strength(DEFAULT_MUSCLE_STRENGTH) { - _childOffset = child->_position - parent->_position; -} - -float MuscleConstraint::enforce() { - _childPoint->_position += _strength * (_rootPoint->_position + _childOffset - _childPoint->_position); - return 0.0f; -} - -void MuscleConstraint::setIndices(int parent, int child) { - _parentIndex = parent; - _childndex = child; -} - diff --git a/interface/src/avatar/MuscleConstraint.h b/interface/src/avatar/MuscleConstraint.h deleted file mode 100644 index b2387a33f0..0000000000 --- a/interface/src/avatar/MuscleConstraint.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// MuscleConstraint.h -// interface/src/avatar -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_MuscleConstraint_h -#define hifi_MuscleConstraint_h - -#include - -// MuscleConstraint is a simple constraint that pushes the child toward an offset relative to the parent. -// It does NOT push the parent. - -const float MAX_MUSCLE_STRENGTH = 0.75f; - -class MuscleConstraint : public Constraint { -public: - MuscleConstraint(VerletPoint* parent, VerletPoint* child); - MuscleConstraint(const MuscleConstraint& other); - float enforce(); - - void setIndices(int parent, int child); - int getParentIndex() const { return _parentIndex; } - int getChildIndex() const { return _childndex; } - void setChildOffset(const glm::vec3& offset) { _childOffset = offset; } - void setStrength(float strength) { _strength = glm::clamp(strength, 0.0f, MAX_MUSCLE_STRENGTH); } - float getStrength() const { return _strength; } -private: - VerletPoint* _rootPoint; - VerletPoint* _childPoint; - int _parentIndex; - int _childndex; - glm::vec3 _childOffset; - float _strength; // a value in range [0,MAX_MUSCLE_STRENGTH] -}; - -#endif // hifi_MuscleConstraint_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 82aa4e8177..9ecc0a3798 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -72,7 +72,6 @@ MyAvatar::MyAvatar() : Avatar(), _turningKeyPressTime(0.0f), _gravity(0.0f, 0.0f, 0.0f), - _distanceToNearestAvatar(std::numeric_limits::max()), _shouldJump(false), _wasPushing(false), _isPushing(false), @@ -88,7 +87,6 @@ MyAvatar::MyAvatar() : _lookAtTargetAvatar(), _shouldRender(true), _billboardValid(false), - _physicsSimulation(), _feetTouchFloor(true), _isLookingAtLeftEye(true), _realWorldFieldOfView("realWorldFieldOfView", @@ -98,18 +96,15 @@ MyAvatar::MyAvatar() : for (int i = 0; i < MAX_DRIVE_KEYS; i++) { _driveKeys[i] = 0.0f; } - _physicsSimulation.setEntity(&_skeletonModel); _skeletonModel.setEnableShapes(true); - _skeletonModel.buildRagdoll(); - + // connect to AddressManager signal for location jumps connect(DependencyManager::get().data(), &AddressManager::locationChangeRequired, this, &MyAvatar::goToLocation); } MyAvatar::~MyAvatar() { - _physicsSimulation.clear(); _lookAtTargetAvatar.clear(); } @@ -176,7 +171,6 @@ void MyAvatar::simulate(float deltaTime) { setScale(scale); Application::getInstance()->getCamera()->setScale(scale); } - _skeletonModel.setShowTrueJointTransforms(! Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)); { PerformanceTimer perfTimer("transform"); @@ -213,16 +207,9 @@ void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("joints"); // copy out the skeleton joints from the model _jointData.resize(_skeletonModel.getJointStateCount()); - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - for (int i = 0; i < _jointData.size(); i++) { - JointData& data = _jointData[i]; - data.valid = _skeletonModel.getVisibleJointState(i, data.rotation); - } - } else { - for (int i = 0; i < _jointData.size(); i++) { - JointData& data = _jointData[i]; - data.valid = _skeletonModel.getJointState(i, data.rotation); - } + for (int i = 0; i < _jointData.size(); i++) { + JointData& data = _jointData[i]; + data.valid = _skeletonModel.getJointState(i, data.rotation); } } @@ -238,54 +225,6 @@ void MyAvatar::simulate(float deltaTime) { head->simulate(deltaTime, true); } - { - PerformanceTimer perfTimer("physics"); - const float minError = 0.00001f; - const float maxIterations = 3; - const quint64 maxUsec = 4000; - _physicsSimulation.setTranslation(_position); - _physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec); - - Ragdoll* ragdoll = _skeletonModel.getRagdoll(); - if (ragdoll && Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - // harvest any displacement of the Ragdoll that is a result of collisions - glm::vec3 ragdollDisplacement = ragdoll->getAndClearAccumulatedMovement(); - const float MAX_RAGDOLL_DISPLACEMENT_2 = 1.0f; - float length2 = glm::length2(ragdollDisplacement); - if (length2 > EPSILON && length2 < MAX_RAGDOLL_DISPLACEMENT_2) { - applyPositionDelta(ragdollDisplacement); - } - } else { - _skeletonModel.moveShapesTowardJoints(1.0f); - } - } - - // now that we're done stepping the avatar forward in time, compute new collisions - if (_collisionGroups != 0) { - PerformanceTimer perfTimer("collisions"); - Camera* myCamera = Application::getInstance()->getCamera(); - - float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE; - if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) { - radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.0f)); - radius *= COLLISION_RADIUS_SCALAR; - } - if (_collisionGroups & COLLISION_GROUP_ENVIRONMENT) { - PerformanceTimer perfTimer("environment"); - updateCollisionWithEnvironment(deltaTime, radius); - } - if (_collisionGroups & COLLISION_GROUP_VOXELS) { - PerformanceTimer perfTimer("voxels"); - updateCollisionWithVoxels(deltaTime, radius); - } else { - _trapDuration = 0.0f; - } - if (_collisionGroups & COLLISION_GROUP_AVATARS) { - PerformanceTimer perfTimer("avatars"); - updateCollisionWithAvatars(deltaTime); - } - } - // Record avatars movements. if (_recorder && _recorder->isRecording()) { _recorder->record(); @@ -1305,14 +1244,6 @@ void MyAvatar::updatePosition(float deltaTime) { intersection._rayStart = glm::vec3(0.0f); intersection._rayDirection = - _worldUpDirection; intersection._rayLength = 4.0f * boundingShape.getBoundingRadius(); - if (_physicsSimulation.findFloorRayIntersection(intersection)) { - // NOTE: heightAboveFloor is the distance between the bottom of the avatar and the floor - heightAboveFloor = intersection._hitDistance - boundingShape.getBoundingRadius() - + _skeletonModel.getBoundingShapeOffset().y; - if (heightAboveFloor < maxFloorDistance) { - hasFloor = true; - } - } // velocity is initialized to the measured _velocity but will be modified by friction, external thrust, etc glm::vec3 velocity = _velocity; @@ -1397,7 +1328,6 @@ void MyAvatar::updatePosition(float deltaTime) { const float MOVING_SPEED_THRESHOLD = 0.01f; _moving = speed > MOVING_SPEED_THRESHOLD; - updateChatCircle(deltaTime); measureMotionDerivatives(deltaTime); } @@ -1420,169 +1350,6 @@ void MyAvatar::updatePositionWithPhysics(float deltaTime) { _velocity = rotation * newLocalVelocity; } -void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) { - glm::vec3 up = getBodyUpDirection(); - const float ENVIRONMENT_SURFACE_ELASTICITY = 0.0f; - const float ENVIRONMENT_SURFACE_DAMPING = 0.01f; - const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; - glm::vec3 penetration; - float pelvisFloatingHeight = getPelvisFloatingHeight(); - if (Application::getInstance()->getEnvironment()->findCapsulePenetration( - _position - up * (pelvisFloatingHeight - radius), - _position + up * (getSkeletonHeight() - pelvisFloatingHeight + radius), radius, penetration)) { - updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); - applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); - } -} - -static CollisionList myCollisions(64); - -void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { - - // TODO: Andrew to do ground/walking detection in ragdoll mode - if (!Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - const float MAX_VOXEL_COLLISION_SPEED = 100.0f; - float speed = glm::length(_velocity); - if (speed > MAX_VOXEL_COLLISION_SPEED) { - // don't even bother to try to collide against voxles when moving very fast - _trapDuration = 0.0f; - return; - } - bool isTrapped = false; - myCollisions.clear(); - // copy the boundingShape and tranform into physicsSimulation frame - CapsuleShape boundingShape = _skeletonModel.getBoundingShape(); - boundingShape.setTranslation(boundingShape.getTranslation() - _position); - - if (_physicsSimulation.getShapeCollisions(&boundingShape, myCollisions)) { - // we temporarily move b - const float VOXEL_ELASTICITY = 0.0f; - const float VOXEL_DAMPING = 0.0f; - const float capsuleRadius = boundingShape.getRadius(); - const float capsuleHalfHeight = boundingShape.getHalfHeight(); - const float MAX_STEP_HEIGHT = capsuleRadius + capsuleHalfHeight; - const float MIN_STEP_HEIGHT = 0.0f; - float highestStep = 0.0f; - float lowestStep = MAX_STEP_HEIGHT; - glm::vec3 floorPoint; - glm::vec3 stepPenetration(0.0f); - glm::vec3 totalPenetration(0.0f); - - for (int i = 0; i < myCollisions.size(); ++i) { - CollisionInfo* collision = myCollisions[i]; - - float verticalDepth = glm::dot(collision->_penetration, _worldUpDirection); - float horizontalDepth = glm::length(collision->_penetration - verticalDepth * _worldUpDirection); - const float MAX_TRAP_PERIOD = 0.125f; - if (horizontalDepth > capsuleRadius || fabsf(verticalDepth) > MAX_STEP_HEIGHT) { - isTrapped = true; - if (_trapDuration > MAX_TRAP_PERIOD) { - RayIntersectionInfo intersection; - // we pick a rayStart that we expect to be inside the boundingShape (aka shapeA) - intersection._rayStart = collision->_contactPoint - MAX_STEP_HEIGHT * glm::normalize(collision->_penetration); - intersection._rayDirection = -_worldUpDirection; - // cast the ray down against shapeA - if (collision->_shapeA->findRayIntersection(intersection)) { - float firstDepth = - intersection._hitDistance; - // recycle intersection and cast again in up against shapeB - intersection._rayDirection = _worldUpDirection; - intersection._hitDistance = FLT_MAX; - if (collision->_shapeB->findRayIntersection(intersection)) { - // now we know how much we need to move UP to get out - totalPenetration = addPenetrations(totalPenetration, - (firstDepth + intersection._hitDistance) * _worldUpDirection); - } - } - continue; - } - } else if (_trapDuration > MAX_TRAP_PERIOD) { - // we're trapped, ignore this shallow collision - continue; - } - totalPenetration = addPenetrations(totalPenetration, collision->_penetration); - - // some logic to help us walk up steps - if (glm::dot(collision->_penetration, _velocity) >= 0.0f) { - float stepHeight = - glm::dot(_worldUpDirection, collision->_penetration); - if (stepHeight > highestStep) { - highestStep = stepHeight; - stepPenetration = collision->_penetration; - } - if (stepHeight < lowestStep) { - lowestStep = stepHeight; - // remember that collision is in _physicsSimulation frame so we must add _position - floorPoint = _position + collision->_contactPoint - collision->_penetration; - } - } - } - - float penetrationLength = glm::length(totalPenetration); - if (penetrationLength < EPSILON) { - _trapDuration = 0.0f; - return; - } - float verticalPenetration = glm::dot(totalPenetration, _worldUpDirection); - if (highestStep > MIN_STEP_HEIGHT && highestStep < MAX_STEP_HEIGHT && verticalPenetration <= 0.0f) { - // we're colliding against an edge - - // rotate _keyboardMotorVelocity into world frame - glm::vec3 targetVelocity = _keyboardMotorVelocity; - glm::quat rotation = getHead()->getCameraOrientation(); - targetVelocity = rotation * _keyboardMotorVelocity; - if (_wasPushing && glm::dot(targetVelocity, totalPenetration) > EPSILON) { - // we're puhing into the edge, so we want to lift - - // remove unhelpful horizontal component of the step's penetration - totalPenetration -= stepPenetration - (glm::dot(stepPenetration, _worldUpDirection) * _worldUpDirection); - - // further adjust penetration to help lift - float liftSpeed = glm::max(MAX_WALKING_SPEED, speed); - float thisStep = glm::min(liftSpeed * deltaTime, highestStep); - float extraStep = glm::dot(totalPenetration, _worldUpDirection) + thisStep; - if (extraStep > 0.0f) { - totalPenetration -= extraStep * _worldUpDirection; - } - - _position -= totalPenetration; - } else { - // we're not pushing into the edge, so let the avatar fall - applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); - } - } else { - applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING); - } - - // Don't make a collision sound against voxlels by default -- too annoying when walking - //const float VOXEL_COLLISION_FREQUENCY = 0.5f; - //updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); - } - _trapDuration = isTrapped ? _trapDuration + deltaTime : 0.0f; - } -} - -void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { - // - // Update the avatar in response to a hard collision. Position will be reset exactly - // to outside the colliding surface. Velocity will be modified according to elasticity. - // - // if elasticity = 0.0, collision is 100% inelastic. - // if elasticity = 1.0, collision is elastic. - // - _position -= penetration; - static float HALTING_VELOCITY = 0.2f; - // cancel out the velocity component in the direction of penetration - float penetrationLength = glm::length(penetration); - if (penetrationLength > EPSILON) { - glm::vec3 direction = penetration / penetrationLength; - _velocity -= glm::dot(_velocity, direction) * direction * (1.0f + elasticity); - _velocity *= glm::clamp(1.0f - damping, 0.0f, 1.0f); - if ((glm::length(_velocity) < HALTING_VELOCITY) && (glm::length(_thrust) == 0.0f)) { - // If moving really slowly after a collision, and not applying forces, stop altogether - _velocity *= 0.0f; - } - } -} - void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { // COLLISION SOUND API in Audio has been removed } @@ -1625,173 +1392,6 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float return false; } -void MyAvatar::updateCollisionWithAvatars(float deltaTime) { - // Reset detector for nearest avatar - _distanceToNearestAvatar = std::numeric_limits::max(); - const AvatarHash& avatars = DependencyManager::get()->getAvatarHash(); - if (avatars.size() <= 1) { - // no need to compute a bunch of stuff if we have one or fewer avatars - return; - } - float myBoundingRadius = getBoundingRadius(); - - // find nearest avatar - float nearestDistance2 = std::numeric_limits::max(); - Avatar* nearestAvatar = NULL; - foreach (const AvatarSharedPointer& avatarPointer, avatars) { - Avatar* avatar = static_cast(avatarPointer.data()); - if (static_cast(this) == avatar) { - // don't collide with ourselves - continue; - } - float distance2 = glm::distance2(_position, avatar->getPosition()); - if (nearestDistance2 > distance2) { - nearestDistance2 = distance2; - nearestAvatar = avatar; - } - } - _distanceToNearestAvatar = glm::sqrt(nearestDistance2); - - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - if (nearestAvatar != NULL) { - if (_distanceToNearestAvatar > myBoundingRadius + nearestAvatar->getBoundingRadius()) { - // they aren't close enough to put into the _physicsSimulation - // so we clear the pointer - nearestAvatar = NULL; - } - } - - foreach (const AvatarSharedPointer& avatarPointer, avatars) { - Avatar* avatar = static_cast(avatarPointer.data()); - if (static_cast(this) == avatar) { - // don't collide with ourselves - continue; - } - SkeletonModel* skeleton = &(avatar->getSkeletonModel()); - PhysicsSimulation* simulation = skeleton->getSimulation(); - if (avatar == nearestAvatar) { - if (simulation != &(_physicsSimulation)) { - skeleton->setEnableShapes(true); - _physicsSimulation.addEntity(skeleton); - _physicsSimulation.addRagdoll(skeleton->getRagdoll()); - } - } else if (simulation == &(_physicsSimulation)) { - _physicsSimulation.removeRagdoll(skeleton->getRagdoll()); - _physicsSimulation.removeEntity(skeleton); - skeleton->setEnableShapes(false); - } - } - } -} - -class SortedAvatar { -public: - Avatar* avatar; - float distance; - glm::vec3 accumulatedCenter; -}; - -bool operator<(const SortedAvatar& s1, const SortedAvatar& s2) { - return s1.distance < s2.distance; -} - -void MyAvatar::updateChatCircle(float deltaTime) { - if (!(_isChatCirclingEnabled = Menu::getInstance()->isOptionChecked(MenuOption::ChatCircling))) { - return; - } - - // find all circle-enabled members and sort by distance - QVector sortedAvatars; - - foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get()->getAvatarHash()) { - Avatar* avatar = static_cast(avatarPointer.data()); - if ( ! avatar->isChatCirclingEnabled() || - avatar == static_cast(this)) { - continue; - } - - SortedAvatar sortedAvatar; - sortedAvatar.avatar = avatar; - sortedAvatar.distance = glm::distance(_position, sortedAvatar.avatar->getPosition()); - sortedAvatars.append(sortedAvatar); - } - - qSort(sortedAvatars.begin(), sortedAvatars.end()); - - // compute the accumulated centers - glm::vec3 center = _position; - for (int i = 0; i < sortedAvatars.size(); i++) { - SortedAvatar& sortedAvatar = sortedAvatars[i]; - sortedAvatar.accumulatedCenter = (center += sortedAvatar.avatar->getPosition()) / (i + 2.0f); - } - - // remove members whose accumulated circles are too far away to influence us - const float CIRCUMFERENCE_PER_MEMBER = 0.5f; - const float CIRCLE_INFLUENCE_SCALE = 2.0f; - const float MIN_RADIUS = 0.3f; - for (int i = sortedAvatars.size() - 1; i >= 0; i--) { - float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / TWO_PI); - if (glm::distance(_position, sortedAvatars[i].accumulatedCenter) > radius * CIRCLE_INFLUENCE_SCALE) { - sortedAvatars.remove(i); - } else { - break; - } - } - if (sortedAvatars.isEmpty()) { - return; - } - center = sortedAvatars.last().accumulatedCenter; - float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / TWO_PI); - - // compute the average up vector - glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP; - foreach (const SortedAvatar& sortedAvatar, sortedAvatars) { - up += sortedAvatar.avatar->getWorldAlignedOrientation() * IDENTITY_UP; - } - up = glm::normalize(up); - - // find reasonable corresponding right/front vectors - glm::vec3 front = glm::cross(up, IDENTITY_RIGHT); - if (glm::length(front) < EPSILON) { - front = glm::cross(up, IDENTITY_FRONT); - } - front = glm::normalize(front); - glm::vec3 right = glm::cross(front, up); - - // find our angle and the angular distances to our closest neighbors - glm::vec3 delta = _position - center; - glm::vec3 projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f); - float myAngle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f; - float leftDistance = TWO_PI; - float rightDistance = TWO_PI; - foreach (const SortedAvatar& sortedAvatar, sortedAvatars) { - delta = sortedAvatar.avatar->getPosition() - center; - projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f); - float angle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f; - if (angle < myAngle) { - leftDistance = min(myAngle - angle, leftDistance); - rightDistance = min(TWO_PI - (myAngle - angle), rightDistance); - - } else { - leftDistance = min(TWO_PI - (angle - myAngle), leftDistance); - rightDistance = min(angle - myAngle, rightDistance); - } - } - - // if we're on top of a neighbor, we need to randomize so that they don't both go in the same direction - if (rightDistance == 0.0f && randomBoolean()) { - swap(leftDistance, rightDistance); - } - - // split the difference between our neighbors - float targetAngle = myAngle + (rightDistance - leftDistance) / 4.0f; - glm::vec3 targetPosition = center + (front * sinf(targetAngle) + right * cosf(targetAngle)) * radius; - - // approach the target position - const float APPROACH_RATE = 0.05f; - _position = glm::mix(_position, targetPosition, APPROACH_RATE); -} - void MyAvatar::maybeUpdateBillboard() { if (_billboardValid || !(_skeletonModel.isLoadedWithTextures() && getHead()->getFaceModel().isLoadedWithTextures())) { return; @@ -1894,17 +1494,6 @@ void MyAvatar::updateMotionBehavior() { _feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations); } -void MyAvatar::onToggleRagdoll() { - Ragdoll* ragdoll = _skeletonModel.getRagdoll(); - if (ragdoll) { - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - _physicsSimulation.setRagdoll(ragdoll); - } else { - _physicsSimulation.setRagdoll(NULL); - } - } -} - void MyAvatar::renderAttachments(RenderMode renderMode, RenderArgs* args) { if (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON || renderMode == MIRROR_RENDER_MODE) { Avatar::renderAttachments(renderMode, args); @@ -1922,38 +1511,6 @@ void MyAvatar::renderAttachments(RenderMode renderMode, RenderArgs* args) { } } -void MyAvatar::setCollisionGroups(quint32 collisionGroups) { - Avatar::setCollisionGroups(collisionGroups & VALID_COLLISION_GROUPS); - Menu* menu = Menu::getInstance(); - menu->setIsOptionChecked(MenuOption::CollideWithEnvironment, (bool)(_collisionGroups & COLLISION_GROUP_ENVIRONMENT)); - menu->setIsOptionChecked(MenuOption::CollideWithAvatars, (bool)(_collisionGroups & COLLISION_GROUP_AVATARS)); - - // TODO: what to do about this now that voxels are gone - if (! (_collisionGroups & COLLISION_GROUP_VOXELS)) { - // no collision with voxels --> disable standing on floors - _motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; - menu->setIsOptionChecked(MenuOption::StandOnNearbyFloors, false); - } -} - -void MyAvatar::applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { - glm::vec3 leverAxis = contactPoint - getPosition(); - float leverLength = glm::length(leverAxis); - if (leverLength > EPSILON) { - // compute lean perturbation angles - glm::quat bodyRotation = getOrientation(); - glm::vec3 xAxis = bodyRotation * glm::vec3(1.0f, 0.0f, 0.0f); - glm::vec3 zAxis = bodyRotation * glm::vec3(0.0f, 0.0f, 1.0f); - - leverAxis = leverAxis / leverLength; - glm::vec3 effectivePenetration = penetration - glm::dot(penetration, leverAxis) * leverAxis; - // use the small-angle approximation for sine - float sideways = - glm::dot(effectivePenetration, xAxis) / leverLength; - float forward = glm::dot(effectivePenetration, zAxis) / leverLength; - getHead()->addLeanDeltas(sideways, forward); - } -} - //Renders sixense laser pointers for UI selection with controllers void MyAvatar::renderLaserPointers() { const float PALM_TIP_ROD_RADIUS = 0.002f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 7e7281f6a1..7376acfdcb 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -12,7 +12,6 @@ #ifndef hifi_MyAvatar_h #define hifi_MyAvatar_h -#include #include #include "Avatar.h" @@ -139,10 +138,6 @@ public: const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f, bool allowDuplicates = false, bool useSaved = true); - virtual void setCollisionGroups(quint32 collisionGroups); - - void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration); - /// Renders a laser pointer for UI picking void renderLaserPointers(); glm::vec3 getLaserPointerTipPosition(const PalmData* palm); @@ -165,7 +160,6 @@ public slots: void setThrust(glm::vec3 newThrust) { _thrust = newThrust; } void updateMotionBehavior(); - void onToggleRagdoll(); glm::vec3 getLeftPalmPosition(); glm::vec3 getRightPalmPosition(); @@ -190,7 +184,6 @@ protected: private: float _turningKeyPressTime; glm::vec3 _gravity; - float _distanceToNearestAvatar; // How close is the nearest avatar? bool _shouldJump; float _driveKeys[MAX_DRIVE_KEYS]; @@ -215,7 +208,6 @@ private: float _oculusYawOffset; QList _animationHandles; - PhysicsSimulation _physicsSimulation; bool _feetTouchFloor; bool _isLookingAtLeftEye; @@ -232,12 +224,7 @@ private: glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity); void updatePosition(float deltaTime); void updatePositionWithPhysics(float deltaTime); - void updateCollisionWithAvatars(float deltaTime); - void updateCollisionWithEnvironment(float deltaTime, float radius); - void updateCollisionWithVoxels(float deltaTime, float radius); - void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); - void updateChatCircle(float deltaTime); void maybeUpdateBillboard(); void setGravity(const glm::vec3& gravity); }; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index fbb622b30a..d083116ecd 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -12,15 +12,14 @@ #include #include -#include -#include +#include +#include #include "Application.h" #include "Avatar.h" #include "Hand.h" #include "Menu.h" #include "SkeletonModel.h" -#include "SkeletonRagdoll.h" #include "Util.h" enum StandingFootState { @@ -35,7 +34,6 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : _owningAvatar(owningAvatar), _boundingShape(), _boundingShapeLocalOffset(0.0f), - _ragdoll(NULL), _defaultEyeModelPosition(glm::vec3(0.0f, 0.0f, 0.0f)), _standingFoot(NO_FOOT), _standingOffset(0.0f), @@ -44,8 +42,6 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : } SkeletonModel::~SkeletonModel() { - delete _ragdoll; - _ragdoll = NULL; } void SkeletonModel::setJointStates(QVector states) { @@ -175,12 +171,6 @@ void SkeletonModel::getHandShapes(int jointIndex, QVector& shapes) } } -void SkeletonModel::getBodyShapes(QVector& shapes) const { - // for now we push a single bounding shape, - // but later we could push a subset of joint shapes - shapes.push_back(&_boundingShape); -} - void SkeletonModel::renderIKConstraints() { renderJointConstraints(getRightHandJointIndex()); renderJointConstraints(getLeftHandJointIndex()); @@ -496,10 +486,6 @@ bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const { } bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { - if (_owningAvatar->isMyAvatar() && - Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - return isActive() && getVisibleJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); - } return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); } @@ -513,12 +499,7 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP } int parentIndex = geometry.joints.at(geometry.neckJointIndex).parentIndex; glm::quat worldFrameRotation; - bool success = false; - if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { - success = getVisibleJointRotationInWorldFrame(parentIndex, worldFrameRotation); - } else { - success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation); - } + bool success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation); if (success) { neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation; } @@ -565,83 +546,6 @@ glm::vec3 SkeletonModel::getDefaultEyeModelPosition() const { return _owningAvatar->getScale() * _defaultEyeModelPosition; } -void SkeletonModel::renderRagdoll() { - if (!_ragdoll) { - return; - } - const QVector& points = _ragdoll->getPoints(); - const int BALL_SUBDIVISIONS = 6; - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glPushMatrix(); - - Application::getInstance()->loadTranslatedViewMatrix(_translation); - int numPoints = points.size(); - float alpha = 0.3f; - float radius1 = 0.008f; - float radius2 = 0.01f; - glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); - auto geometryCache = DependencyManager::get(); - for (int i = 0; i < numPoints; ++i) { - glPushMatrix(); - // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative - glm::vec3 position = points[i]._position - simulationTranslation; - glTranslatef(position.x, position.y, position.z); - // draw each point as a yellow hexagon with black border - geometryCache->renderSphere(radius2, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.0f, 0.0f, 0.0f, alpha)); - geometryCache->renderSphere(radius1, BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(1.0f, 1.0f, 0.0f, alpha)); - glPopMatrix(); - } - glPopMatrix(); - glEnable(GL_DEPTH_TEST); - glEnable(GL_LIGHTING); -} - -void SkeletonModel::updateVisibleJointStates() { - if (_showTrueJointTransforms || !_ragdoll) { - // no need to update visible transforms - return; - } - const QVector& ragdollPoints = _ragdoll->getPoints(); - QVector points; - points.reserve(_jointStates.size()); - glm::quat invRotation = glm::inverse(_rotation); - for (int i = 0; i < _jointStates.size(); i++) { - JointState& state = _jointStates[i]; - points.push_back(ragdollPoints[i]._position); - - // get the parent state (this is the state that we want to rotate) - int parentIndex = state.getParentIndex(); - if (parentIndex == -1) { - _jointStates[i].slaveVisibleTransform(); - continue; - } - JointState& parentState = _jointStates[parentIndex]; - - // check the grand-parent index (for now we don't want to rotate any root states) - int grandParentIndex = parentState.getParentIndex(); - if (grandParentIndex == -1) { - continue; - } - - // make sure state's visibleTransform is up to date - const glm::mat4& parentTransform = parentState.getVisibleTransform(); - state.computeVisibleTransform(parentTransform); - - // we're looking for the rotation that moves visible bone parallel to ragdoll bone - // rotationBetween(jointTip - jointPivot, shapeTip - shapePivot) - // NOTE: points are in simulation-frame so rotate line segment into model-frame - glm::quat delta = rotationBetween(state.getVisiblePosition() - extractTranslation(parentTransform), - invRotation * (points[i] - points[parentIndex])); - - // apply - parentState.mixVisibleRotationDelta(delta, 0.01f); - // update transforms - parentState.computeVisibleTransform(_jointStates[grandParentIndex].getVisibleTransform()); - state.computeVisibleTransform(parentState.getVisibleTransform()); - } -} - /// \return offset of hips after foot animation void SkeletonModel::updateStandingFoot() { if (_geometry == NULL) { @@ -701,17 +605,6 @@ void SkeletonModel::updateStandingFoot() { _standingOffset = offset; } -SkeletonRagdoll* SkeletonModel::buildRagdoll() { - if (!_ragdoll) { - _ragdoll = new SkeletonRagdoll(this); - if (_enableShapes) { - clearShapes(); - buildShapes(); - } - } - return _ragdoll; -} - float DENSITY_OF_WATER = 1000.0f; // kg/m^3 float MIN_JOINT_MASS = 1.0f; float VERY_BIG_MASS = 1.0e6f; @@ -728,18 +621,8 @@ void SkeletonModel::buildShapes() { return; } - if (!_ragdoll) { - _ragdoll = new SkeletonRagdoll(this); - } - _ragdoll->setRootIndex(geometry.rootJointIndex); - _ragdoll->initPoints(); - QVector& points = _ragdoll->getPoints(); - - float massScale = _ragdoll->getMassScale(); - float uniformScale = extractUniformScale(_scale); const int numStates = _jointStates.size(); - float totalMass = 0.0f; for (int i = 0; i < numStates; i++) { JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); @@ -755,18 +638,12 @@ void SkeletonModel::buildShapes() { } Shape* shape = NULL; if (type == SPHERE_SHAPE) { - shape = new VerletSphereShape(radius, &(points[i])); + shape = new SphereShape(radius); shape->setEntity(this); - float mass = massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); - points[i].setMass(mass); - totalMass += mass; } else if (type == CAPSULE_SHAPE) { assert(parentIndex != -1); - shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i])); + shape = new CapsuleShape(radius, halfHeight); shape->setEntity(this); - float mass = massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume()); - points[i].setMass(mass); - totalMass += mass; } if (shape && parentIndex != -1) { // always disable collisions between joint and its parent @@ -775,47 +652,8 @@ void SkeletonModel::buildShapes() { _shapes.push_back(shape); } - // set the mass of the root - if (numStates > 0) { - points[_ragdoll->getRootIndex()].setMass(totalMass); - } - // This method moves the shapes to their default positions in Model frame. computeBoundingShape(geometry); - - // While the shapes are in their default position we disable collisions between - // joints that are currently colliding. - disableCurrentSelfCollisions(); - - _ragdoll->buildConstraints(); - - // ... then move shapes back to current joint positions - _ragdoll->slamPointPositions(); - _ragdoll->enforceConstraints(); -} - -void SkeletonModel::moveShapesTowardJoints(float deltaTime) { - // KEEP: although we don't currently use this method we may eventually need it to help - // unravel a skelton that has become tangled in its constraints. So let's keep this - // around for a while just in case. - const int numStates = _jointStates.size(); - QVector& ragdollPoints = _ragdoll->getPoints(); - assert(_jointStates.size() == ragdollPoints.size()); - if (ragdollPoints.size() != numStates) { - return; - } - - // fraction = 0 means keep old position, = 1 means slave 100% to target position - const float RAGDOLL_FOLLOWS_JOINTS_TIMESCALE = 0.05f; - float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f); - - float oneMinusFraction = 1.0f - fraction; - glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); - for (int i = 0; i < numStates; ++i) { - // ragdollPoints are in simulation-frame but jointStates are in model-frame - ragdollPoints[i].initPosition(oneMinusFraction * ragdollPoints[i]._position + - fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition()))); - } } void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { @@ -824,25 +662,21 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { QVector transforms; transforms.fill(glm::mat4(), numStates); - QVector& ragdollPoints = _ragdoll->getPoints(); - - // compute the default transforms and slam the ragdoll positions accordingly - // (which puts the shapes where we want them) + // compute the default transforms for (int i = 0; i < numStates; i++) { JointState& state = _jointStates[i]; const FBXJoint& joint = state.getFBXJoint(); int parentIndex = joint.parentIndex; if (parentIndex == -1) { transforms[i] = _jointStates[i].getTransform(); - ragdollPoints[i].initPosition(extractTranslation(transforms[i])); continue; } glm::quat modifiedRotation = joint.preRotation * joint.rotation * joint.postRotation; transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; - // setting the ragdollPoints here slams the VerletShapes into their default positions - ragdollPoints[i].initPosition(extractTranslation(transforms[i])); + // TODO: Andrew to harvest transforms here to move shapes to correct positions so that + // bounding capsule calculations below are correct. } // compute bounding box that encloses all shapes @@ -959,56 +793,6 @@ void SkeletonModel::renderBoundingCollisionShapes(float alpha) { const int BALL_SUBDIVISIONS = 10; -// virtual -void SkeletonModel::renderJointCollisionShapes(float alpha) { - if (!_ragdoll) { - return; - } - glPushMatrix(); - Application::getInstance()->loadTranslatedViewMatrix(_translation); - glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); - for (int i = 0; i < _shapes.size(); i++) { - Shape* shape = _shapes[i]; - if (!shape) { - continue; - } - - auto geometryCache = DependencyManager::get(); - - glPushMatrix(); - // shapes are stored in simulation-frame but we want position to be model-relative - if (shape->getType() == SPHERE_SHAPE) { - glm::vec3 position = shape->getTranslation() - simulationTranslation; - glTranslatef(position.x, position.y, position.z); - // draw a grey sphere at shape position - geometryCache->renderSphere(shape->getBoundingRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.75f, 0.75f, 0.75f, alpha)); - } else if (shape->getType() == CAPSULE_SHAPE) { - CapsuleShape* capsule = static_cast(shape); - - // draw a blue sphere at the capsule endpoint - glm::vec3 endPoint; - capsule->getEndPoint(endPoint); - endPoint = endPoint - simulationTranslation; - glTranslatef(endPoint.x, endPoint.y, endPoint.z); - geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.6f, 0.6f, 0.8f, alpha)); - - // draw a yellow sphere at the capsule startpoint - glm::vec3 startPoint; - capsule->getStartPoint(startPoint); - startPoint = startPoint - simulationTranslation; - glm::vec3 axis = endPoint - startPoint; - glTranslatef(-axis.x, -axis.y, -axis.z); - geometryCache->renderSphere(capsule->getRadius(), BALL_SUBDIVISIONS, BALL_SUBDIVISIONS, glm::vec4(0.8f, 0.8f, 0.6f, alpha)); - - // draw a green cylinder between the two points - glm::vec3 origin(0.0f); - Avatar::renderJointConnectingCone( origin, axis, capsule->getRadius(), capsule->getRadius(), glm::vec4(0.6f, 0.8f, 0.6f, alpha)); - } - glPopMatrix(); - } - glPopMatrix(); -} - bool SkeletonModel::hasSkeleton() { return isActive() ? _geometry->getFBXGeometry().rootJointIndex != -1 : false; } diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 74d0ed0324..5427fcaf25 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -16,11 +16,8 @@ #include #include -#include "SkeletonRagdoll.h" - class Avatar; class MuscleConstraint; -class SkeletonRagdoll; /// A skeleton loaded from a model. class SkeletonModel : public Model { @@ -39,9 +36,6 @@ public: /// \param shapes[out] list in which is stored pointers to hand shapes void getHandShapes(int jointIndex, QVector& shapes) const; - /// \param shapes[out] list of shapes for body collisions - void getBodyShapes(QVector& shapes) const; - void renderIKConstraints(); /// Returns the index of the left hand joint, or -1 if not found. @@ -106,24 +100,14 @@ public: void updateStandingFoot(); const glm::vec3& getStandingOffset() const { return _standingOffset; } - virtual void updateVisibleJointStates(); - - SkeletonRagdoll* buildRagdoll(); - SkeletonRagdoll* getRagdoll() { return _ragdoll; } - - void moveShapesTowardJoints(float fraction); - void computeBoundingShape(const FBXGeometry& geometry); void renderBoundingCollisionShapes(float alpha); - void renderJointCollisionShapes(float alpha); float getBoundingShapeRadius() const { return _boundingShape.getRadius(); } const CapsuleShape& getBoundingShape() const { return _boundingShape; } const glm::vec3 getBoundingShapeOffset() const { return _boundingShapeLocalOffset; } void resetShapePositionsToDefaultPose(); // DEBUG method - void renderRagdoll(); - bool hasSkeleton(); signals: @@ -171,7 +155,6 @@ private: CapsuleShape _boundingShape; glm::vec3 _boundingShapeLocalOffset; - SkeletonRagdoll* _ragdoll; glm::vec3 _defaultEyeModelPosition; int _standingFoot; diff --git a/interface/src/avatar/SkeletonRagdoll.cpp b/interface/src/avatar/SkeletonRagdoll.cpp deleted file mode 100644 index c944e0bd45..0000000000 --- a/interface/src/avatar/SkeletonRagdoll.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// -// SkeletonRagdoll.cpp -// interface/src/avatar -// -// Created by Andrew Meadows 2014.08.14 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include -#include -#include - -#include "SkeletonRagdoll.h" -#include "MuscleConstraint.h" - -SkeletonRagdoll::SkeletonRagdoll(Model* model) : Ragdoll(), _model(model) { - assert(_model); -} - -SkeletonRagdoll::~SkeletonRagdoll() { -} - -// virtual -void SkeletonRagdoll::stepForward(float deltaTime) { - setTransform(_model->getTranslation(), _model->getRotation()); - Ragdoll::stepForward(deltaTime); - updateMuscles(); - int numConstraints = _muscleConstraints.size(); - for (int i = 0; i < numConstraints; ++i) { - _muscleConstraints[i]->enforce(); - } -} - -void SkeletonRagdoll::slamPointPositions() { - QVector& jointStates = _model->getJointStates(); - const int numPoints = _points.size(); - assert(numPoints == jointStates.size()); - for (int i = _rootIndex; i < numPoints; ++i) { - _points[i].initPosition(jointStates.at(i).getPosition()); - } -} - -// virtual -void SkeletonRagdoll::initPoints() { - clearConstraintsAndPoints(); - _muscleConstraints.clear(); - - initTransform(); - // one point for each joint - int numStates = _model->getJointStates().size(); - _points.fill(VerletPoint(), numStates); - slamPointPositions(); -} - -// virtual -void SkeletonRagdoll::buildConstraints() { - QVector& jointStates = _model->getJointStates(); - - // NOTE: the length of DistanceConstraints is computed and locked in at this time - // so make sure the ragdoll positions are in a normal configuration before here. - const int numPoints = _points.size(); - assert(numPoints == jointStates.size()); - - float minBone = FLT_MAX; - float maxBone = -FLT_MAX; - QMultiMap families; - for (int i = _rootIndex; i < numPoints; ++i) { - const JointState& state = jointStates.at(i); - int parentIndex = state.getParentIndex(); - if (parentIndex != -1) { - DistanceConstraint* bone = new DistanceConstraint(&(_points[i]), &(_points[parentIndex])); - bone->setDistance(state.getDistanceToParent()); - _boneConstraints.push_back(bone); - families.insert(parentIndex, i); - } - float boneLength = glm::length(state.getPositionInParentFrame()); - if (boneLength > maxBone) { - maxBone = boneLength; - } else if (boneLength < minBone) { - minBone = boneLength; - } - } - // Joints that have multiple children effectively have rigid constraints between the children - // in the parent frame, so we add DistanceConstraints between children in the same family. - QMultiMap::iterator itr = families.begin(); - while (itr != families.end()) { - QList children = families.values(itr.key()); - int numChildren = children.size(); - if (numChildren > 1) { - for (int i = 1; i < numChildren; ++i) { - DistanceConstraint* bone = new DistanceConstraint(&(_points[children[i-1]]), &(_points[children[i]])); - _boneConstraints.push_back(bone); - } - if (numChildren > 2) { - DistanceConstraint* bone = new DistanceConstraint(&(_points[children[numChildren-1]]), &(_points[children[0]])); - _boneConstraints.push_back(bone); - } - } - ++itr; - } - - float MAX_STRENGTH = 0.6f; - float MIN_STRENGTH = 0.05f; - // each joint gets a MuscleConstraint to its parent - for (int i = _rootIndex + 1; i < numPoints; ++i) { - const JointState& state = jointStates.at(i); - int p = state.getParentIndex(); - if (p == -1) { - continue; - } - MuscleConstraint* constraint = new MuscleConstraint(&(_points[p]), &(_points[i])); - _muscleConstraints.push_back(constraint); - - // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: - // long = weak and short = strong. - constraint->setIndices(p, i); - float boneLength = glm::length(state.getPositionInParentFrame()); - - float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone); - if (!families.contains(i)) { - // Although muscles only pull on the children not parents, nevertheless those joints that have - // parents AND children are more stable than joints at the end such as fingers. For such joints we - // bestow maximum strength which helps reduce wiggle. - strength = MAX_MUSCLE_STRENGTH; - } - constraint->setStrength(strength); - } -} - -void SkeletonRagdoll::updateMuscles() { - QVector& jointStates = _model->getJointStates(); - int numConstraints = _muscleConstraints.size(); - glm::quat rotation = _model->getRotation(); - for (int i = 0; i < numConstraints; ++i) { - MuscleConstraint* constraint = _muscleConstraints[i]; - int j = constraint->getParentIndex(); - int k = constraint->getChildIndex(); - assert(j != -1 && k != -1); - // ragdollPoints are in simulation-frame but jointStates are in model-frame - constraint->setChildOffset(rotation * (jointStates.at(k).getPosition() - jointStates.at(j).getPosition())); - } -} diff --git a/interface/src/avatar/SkeletonRagdoll.h b/interface/src/avatar/SkeletonRagdoll.h deleted file mode 100644 index 2f8ce1f712..0000000000 --- a/interface/src/avatar/SkeletonRagdoll.h +++ /dev/null @@ -1,43 +0,0 @@ -// -// SkeletonkRagdoll.h -// interface/src/avatar -// -// Created by Andrew Meadows 2014.08.14 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_SkeletonRagdoll_h -#define hifi_SkeletonRagdoll_h - -#include - -#include -#include - -class MuscleConstraint; -class Model; - -class SkeletonRagdoll : public Ragdoll { -public: - - SkeletonRagdoll(Model* model); - virtual ~SkeletonRagdoll(); - - void slamPointPositions(); - virtual void stepForward(float deltaTime); - - virtual void initPoints(); - virtual void buildConstraints(); - -protected: - void updateMuscles(); - -private: - Model* _model; - QVector _muscleConstraints; -}; - -#endif // hifi_SkeletonRagdoll_h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 5b391b33f8..3ab8f38fe6 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -43,7 +43,6 @@ AvatarData::AvatarData() : _targetScale(1.0f), _handState(0), _keyState(NO_KEY_DOWN), - _isChatCirclingEnabled(false), _forceFaceTrackerConnected(false), _hasNewJointRotations(true), _headData(NULL), @@ -195,9 +194,6 @@ QByteArray AvatarData::toByteArray() { if (_headData->_isFaceTrackerConnected) { setAtBit(bitItems, IS_FACESHIFT_CONNECTED); } - if (_isChatCirclingEnabled) { - setAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); - } if (_referential != NULL && _referential->isValid()) { setAtBit(bitItems, HAS_REFERENTIAL); } @@ -419,7 +415,6 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { + (oneAtBit(bitItems, HAND_STATE_FINGER_POINTING_BIT) ? IS_FINGER_POINTING_FLAG : 0); _headData->_isFaceTrackerConnected = oneAtBit(bitItems, IS_FACESHIFT_CONNECTED); - _isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL); // Referential diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index c131588fb0..02b2c364c6 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -91,7 +91,7 @@ const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = const int KEY_STATE_START_BIT = 0; // 1st and 2nd bits const int HAND_STATE_START_BIT = 2; // 3rd and 4th bits const int IS_FACESHIFT_CONNECTED = 4; // 5th bit -const int IS_CHAT_CIRCLING_ENABLED = 5; // 6th bit +const int UNUSED_AVATAR_STATE_BIT_5 = 5; // 6th bit (was CHAT_CIRCLING) const int HAS_REFERENTIAL = 6; // 7th bit const int HAND_STATE_FINGER_POINTING_BIT = 7; // 8th bit @@ -248,7 +248,6 @@ public: void setKeyState(KeyState s) { _keyState = s; } KeyState keyState() const { return _keyState; } - bool isChatCirclingEnabled() const { return _isChatCirclingEnabled; } const HeadData* getHeadData() const { return _headData; } const HandData* getHandData() const { return _handData; } @@ -370,7 +369,6 @@ protected: // key state KeyState _keyState; - bool _isChatCirclingEnabled; bool _forceFaceTrackerConnected; bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar diff --git a/libraries/physics/src/ContactConstraint.cpp b/libraries/physics/src/ContactConstraint.cpp deleted file mode 100644 index 9734922a52..0000000000 --- a/libraries/physics/src/ContactConstraint.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// ContactConstraint.cpp -// libraries/physcis/src -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include "ContactConstraint.h" -#include "VerletPoint.h" - - -ContactConstraint::ContactConstraint(VerletPoint* pointA, VerletPoint* pointB) - : _pointA(pointA), _pointB(pointB), _strength(1.0f) { - assert(_pointA != NULL && _pointB != NULL); - _offset = _pointB->_position - _pointA->_position; -} - -float ContactConstraint::enforce() { - _pointB->_position += _strength * (_pointA->_position + _offset - _pointB->_position); - return 0.0f; -} - -float ContactConstraint::enforceWithNormal(const glm::vec3& normal) { - glm::vec3 delta = _pointA->_position + _offset - _pointB->_position; - - // split delta into parallel (pDelta) and perpendicular (qDelta) components - glm::vec3 pDelta = glm::dot(delta, normal) * normal; - glm::vec3 qDelta = delta - pDelta; - - // use the relative sizes of the components to decide how much perpenducular delta to use - // (i.e. dynamic friction) - float lpDelta = glm::length(pDelta); - float lqDelta = glm::length(qDelta); - float qFactor = lqDelta > lpDelta ? (lpDelta / lqDelta - 1.0f) : 0.0f; - // recombine the two components to get the final delta - delta = pDelta + qFactor * qDelta; - - // attenuate strength by how much _offset is perpendicular to normal - float distance = glm::length(_offset); - float strength = _strength * ((distance > EPSILON) ? glm::abs(glm::dot(_offset, normal)) / distance : 1.0f); - - // move _pointB - _pointB->_position += strength * delta; - - return strength * glm::length(delta); -} - diff --git a/libraries/physics/src/ContactConstraint.h b/libraries/physics/src/ContactConstraint.h deleted file mode 100644 index 44c9c1b879..0000000000 --- a/libraries/physics/src/ContactConstraint.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// ContactConstraint.h -// libraries/physcis/src -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_ContactConstraint_h -#define hifi_ContactConstraint_h - -#include - -#include "Constraint.h" -#include "VerletPoint.h" - -class ContactConstraint : public Constraint { -public: - ContactConstraint(VerletPoint* pointA, VerletPoint* pointB); - - float enforce(); - float enforceWithNormal(const glm::vec3& normal); - - glm::vec3 getTargetPointA() const { return _pointB->_position - _offset; } - - void setOffset(const glm::vec3& offset) { _offset = offset; } - void setStrength(float strength) { _strength = glm::clamp(strength, 0.0f, 1.0f); } - float getStrength() const { return _strength; } -private: - VerletPoint* _pointA; - VerletPoint* _pointB; - glm::vec3 _offset; // from pointA toward pointB - float _strength; // a value in range [0,1] -}; - -#endif // hifi_ContactConstraint_h diff --git a/libraries/physics/src/ContactPoint.cpp b/libraries/physics/src/ContactPoint.cpp deleted file mode 100644 index b949f12582..0000000000 --- a/libraries/physics/src/ContactPoint.cpp +++ /dev/null @@ -1,216 +0,0 @@ -// -// ContactPoint.cpp -// libraries/physics/src -// -// Created by Andrew Meadows 2014.07.30 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include "ContactPoint.h" -#include "Shape.h" - -// This parameter helps keep the actual point of contact slightly inside each shape -// which allows the collisions to happen almost every frame for more frequent updates. -const float CONTACT_PENETRATION_ALLOWANCE = 0.005f; - -ContactPoint::ContactPoint() : - _lastFrame(0), _shapeA(NULL), _shapeB(NULL), - _offsetA(0.0f), _offsetB(0.0f), - _relativeMassA(0.5f), _relativeMassB(0.5f), - _numPointsA(0), _numPoints(0), _normal(0.0f) { -} - -ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : - _lastFrame(frame), _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), - _offsetA(0.0f), _offsetB(0.0f), - _relativeMassA(0.5f), _relativeMassB(0.5f), - _numPointsA(0), _numPoints(0), _normal(0.0f) { - - glm::vec3 pointA = collision._contactPoint; - glm::vec3 pointB = collision._contactPoint - collision._penetration; - - float pLength = glm::length(collision._penetration); - if (pLength > EPSILON) { - _normal = collision._penetration / pLength; - } - if (_shapeA->getID() > _shapeB->getID()) { - // swap so that _shapeA always has lower ID - _shapeA = collision.getShapeB(); - _shapeB = collision.getShapeA(); - _normal = - _normal; - pointA = pointB; - pointB = collision._contactPoint; - } - - // bring the contact points inside the shapes to help maintain collision updates - pointA -= CONTACT_PENETRATION_ALLOWANCE * _normal; - pointB += CONTACT_PENETRATION_ALLOWANCE * _normal; - - _offsetA = pointA - _shapeA->getTranslation(); - _offsetB = pointB - _shapeB->getTranslation(); - - _shapeA->getVerletPoints(_points); - _numPointsA = _points.size(); - _shapeB->getVerletPoints(_points); - _numPoints = _points.size(); - - // compute and cache relative masses - float massA = EPSILON; - for (int i = 0; i < _numPointsA; ++i) { - massA += _points[i]->getMass(); - } - float massB = EPSILON; - for (int i = _numPointsA; i < _numPoints; ++i) { - massB += _points[i]->getMass(); - } - float invTotalMass = 1.0f / (massA + massB); - _relativeMassA = massA * invTotalMass; - _relativeMassB = massB * invTotalMass; - - // _contactPoint will be the weighted average of the two - _contactPoint = _relativeMassA * pointA + _relativeMassB * pointB; - - // compute offsets for shapeA - for (int i = 0; i < _numPointsA; ++i) { - glm::vec3 offset = _points[i]->_position - pointA; - _offsets.push_back(offset); - _distances.push_back(glm::length(offset)); - } - // compute offsets for shapeB - for (int i = _numPointsA; i < _numPoints; ++i) { - glm::vec3 offset = _points[i]->_position - pointB; - _offsets.push_back(offset); - _distances.push_back(glm::length(offset)); - } -} - -float ContactPoint::enforce() { - glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; - glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; - glm::vec3 penetration = pointA - pointB; - float pDotN = glm::dot(penetration, _normal); - bool constraintViolation = (pDotN > CONTACT_PENETRATION_ALLOWANCE); - - // the contact point will be the average of the two points on the shapes - _contactPoint = _relativeMassA * pointA + _relativeMassB * pointB; - - if (constraintViolation) { - for (int i = 0; i < _numPointsA; ++i) { - VerletPoint* point = _points[i]; - glm::vec3 offset = _offsets[i]; - - // split delta into parallel and perpendicular components - glm::vec3 delta = _contactPoint + offset - point->_position; - glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal; - glm::vec3 perpDelta = delta - paraDelta; - - // use the relative sizes of the components to decide how much perpenducular delta to use - // perpendicular < parallel ==> static friction ==> perpFactor = 1.0 - // perpendicular > parallel ==> dynamic friction ==> cap to length of paraDelta ==> perpFactor < 1.0 - float paraLength = _relativeMassB * glm::length(paraDelta); - float perpLength = _relativeMassA * glm::length(perpDelta); - float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; - - // recombine the two components to get the final delta - delta = paraDelta + perpFactor * perpDelta; - - glm::vec3 targetPosition = point->_position + delta; - _distances[i] = glm::distance(_contactPoint, targetPosition); - point->_position += delta; - } - for (int i = _numPointsA; i < _numPoints; ++i) { - VerletPoint* point = _points[i]; - glm::vec3 offset = _offsets[i]; - - // split delta into parallel and perpendicular components - glm::vec3 delta = _contactPoint + offset - point->_position; - glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal; - glm::vec3 perpDelta = delta - paraDelta; - - // use the relative sizes of the components to decide how much perpenducular delta to use - // perpendicular < parallel ==> static friction ==> perpFactor = 1.0 - // perpendicular > parallel ==> dynamic friction ==> cap to length of paraDelta ==> perpFactor < 1.0 - float paraLength = _relativeMassA * glm::length(paraDelta); - float perpLength = _relativeMassB * glm::length(perpDelta); - float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; - - // recombine the two components to get the final delta - delta = paraDelta + perpFactor * perpDelta; - - glm::vec3 targetPosition = point->_position + delta; - _distances[i] = glm::distance(_contactPoint, targetPosition); - point->_position += delta; - } - } else { - for (int i = 0; i < _numPoints; ++i) { - _distances[i] = glm::length(glm::length(_offsets[i])); - } - } - return 0.0f; -} - -// virtual -void ContactPoint::applyFriction() { - // TODO: Andrew to re-implement this in a different way - /* - for (int i = 0; i < _numPoints; ++i) { - glm::vec3& position = _points[i]->_position; - // TODO: use a fast distance approximation - float newDistance = glm::distance(_contactPoint, position); - float constrainedDistance = _distances[i]; - // NOTE: these "distance" constraints only push OUT, don't pull IN. - if (newDistance > EPSILON && newDistance < constrainedDistance) { - glm::vec3 direction = (_contactPoint - position) / newDistance; - glm::vec3 center = 0.5f * (_contactPoint + position); - _contactPoint = center + (0.5f * constrainedDistance) * direction; - position = center - (0.5f * constrainedDistance) * direction; - } - } - */ -} - -void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) { - _lastFrame = frame; - - // compute contact points on surface of each shape - glm::vec3 pointA = collision._contactPoint; - glm::vec3 pointB = pointA - collision._penetration; - - // compute the normal (which points from A into B) - float pLength = glm::length(collision._penetration); - if (pLength > EPSILON) { - _normal = collision._penetration / pLength; - } else { - _normal = glm::vec3(0.0f); - } - - if (collision._shapeA->getID() > collision._shapeB->getID()) { - // our _shapeA always has lower ID - _normal = - _normal; - pointA = pointB; - pointB = collision._contactPoint; - } - - // bring the contact points inside the shapes to help maintain collision updates - pointA -= CONTACT_PENETRATION_ALLOWANCE * _normal; - pointB += CONTACT_PENETRATION_ALLOWANCE * _normal; - - // compute relative offsets to per-shape contact points - _offsetA = pointA - collision._shapeA->getTranslation(); - _offsetB = pointB - collision._shapeB->getTranslation(); - - // compute offsets for shapeA - assert(_offsets.size() == _numPoints); - for (int i = 0; i < _numPointsA; ++i) { - _offsets[i] = _points[i]->_position - pointA; - } - // compute offsets for shapeB - for (int i = _numPointsA; i < _numPoints; ++i) { - _offsets[i] = _points[i]->_position - pointB; - } -} diff --git a/libraries/physics/src/ContactPoint.h b/libraries/physics/src/ContactPoint.h deleted file mode 100644 index c2443f361f..0000000000 --- a/libraries/physics/src/ContactPoint.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// ContactPoint.h -// libraries/physics/src -// -// Created by Andrew Meadows 2014.07.30 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_ContactPoint_h -#define hifi_ContactPoint_h - -#include -#include - -#include - -#include "VerletPoint.h" - -class Shape; - -class ContactPoint { -public: - ContactPoint(); - ContactPoint(const CollisionInfo& collision, quint32 frame); - - virtual float enforce(); - - void applyFriction(); - void updateContact(const CollisionInfo& collision, quint32 frame); - quint32 getLastFrame() const { return _lastFrame; } - - Shape* getShapeA() const { return _shapeA; } - Shape* getShapeB() const { return _shapeB; } - -protected: - quint32 _lastFrame; // frame count of last update - Shape* _shapeA; - Shape* _shapeB; - glm::vec3 _offsetA; // contact point relative to A's center - glm::vec3 _offsetB; // contact point relative to B's center - glm::vec3 _contactPoint; // a "virtual" point that is added to the simulation - float _relativeMassA; // massA / totalMass - float _relativeMassB; // massB / totalMass - int _numPointsA; // number of VerletPoints that belong to _shapeA - int _numPoints; // total number of VerletPoints - QVector _points; // points that belong to colliding shapes - QVector _offsets; // offsets to _points from contactPoint - QVector _distances; // distances to _points from contactPoint (during enforcement stage) - glm::vec3 _normal; // (points from A toward B) -}; - -#endif // hifi_ContactPoint_h diff --git a/libraries/physics/src/DistanceConstraint.cpp b/libraries/physics/src/DistanceConstraint.cpp deleted file mode 100644 index d513c4785b..0000000000 --- a/libraries/physics/src/DistanceConstraint.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// -// DistanceConstraint.cpp -// libraries/physics/src -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include // for EPSILON - -#include "DistanceConstraint.h" -#include "VerletPoint.h" - -DistanceConstraint::DistanceConstraint(VerletPoint* startPoint, VerletPoint* endPoint) : _distance(-1.0f) { - _points[0] = startPoint; - _points[1] = endPoint; - _distance = glm::distance(_points[0]->_position, _points[1]->_position); -} - -DistanceConstraint::DistanceConstraint(const DistanceConstraint& other) { - _distance = other._distance; - _points[0] = other._points[0]; - _points[1] = other._points[1]; -} - -void DistanceConstraint::setDistance(float distance) { - _distance = fabsf(distance); -} - -float DistanceConstraint::enforce() { - // TODO: use a fast distance approximation - float newDistance = glm::distance(_points[0]->_position, _points[1]->_position); - glm::vec3 direction(0.0f, 1.0f, 0.0f); - if (newDistance > EPSILON) { - direction = (_points[0]->_position - _points[1]->_position) / newDistance; - } - glm::vec3 center = 0.5f * (_points[0]->_position + _points[1]->_position); - _points[0]->_position = center + (0.5f * _distance) * direction; - _points[1]->_position = center - (0.5f * _distance) * direction; - return glm::abs(newDistance - _distance); -} diff --git a/libraries/physics/src/DistanceConstraint.h b/libraries/physics/src/DistanceConstraint.h deleted file mode 100644 index 8c2dd38102..0000000000 --- a/libraries/physics/src/DistanceConstraint.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// DistanceConstraint.h -// libraries/physics/src -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_DistanceConstraint_h -#define hifi_DistanceConstraint_h - -#include "Constraint.h" - -class VerletPoint; - -class DistanceConstraint : public Constraint { -public: - DistanceConstraint(VerletPoint* startPoint, VerletPoint* endPoint); - DistanceConstraint(const DistanceConstraint& other); - float enforce(); - void setDistance(float distance); - float getDistance() const { return _distance; } -private: - float _distance; - VerletPoint* _points[2]; -}; - -#endif // hifi_DistanceConstraint_h diff --git a/libraries/physics/src/FixedConstraint.cpp b/libraries/physics/src/FixedConstraint.cpp deleted file mode 100644 index 23f1749fa9..0000000000 --- a/libraries/physics/src/FixedConstraint.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// FixedConstraint.cpp -// libraries/physics/src -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "FixedConstraint.h" -#include "VerletPoint.h" - -FixedConstraint::FixedConstraint(glm::vec3* anchor, VerletPoint* point) : _anchor(anchor), _point(point) { - assert(anchor); - assert(point); -} - -float FixedConstraint::enforce() { - assert(_point != NULL); - _point->_position = *_anchor; - _point->_lastPosition = *_anchor; - return 0.0f; -} - -void FixedConstraint::setAnchor(glm::vec3* anchor) { - assert(anchor); - _anchor = anchor; -} - -void FixedConstraint::setPoint(VerletPoint* point) { - assert(point); - _point = point; -} diff --git a/libraries/physics/src/FixedConstraint.h b/libraries/physics/src/FixedConstraint.h deleted file mode 100644 index 067b9988cd..0000000000 --- a/libraries/physics/src/FixedConstraint.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// FixedConstraint.h -// libraries/physics/src -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_FixedConstraint_h -#define hifi_FixedConstraint_h - -#include - -#include "Constraint.h" - -class VerletPoint; - -// FixedConstraint takes pointers to a glm::vec3 and a VerletPoint. -// The enforcement will copy the value of the vec3 into the VerletPoint. - -class FixedConstraint : public Constraint { -public: - FixedConstraint(glm::vec3* anchor, VerletPoint* point); - ~FixedConstraint() {} - float enforce(); - void setAnchor(glm::vec3* anchor); - void setPoint(VerletPoint* point); -private: - glm::vec3* _anchor; - VerletPoint* _point; -}; - -#endif // hifi_FixedConstraint_h diff --git a/libraries/physics/src/PhysicsEntity.cpp b/libraries/physics/src/PhysicsEntity.cpp index 80176edb76..155b2fe4e0 100644 --- a/libraries/physics/src/PhysicsEntity.cpp +++ b/libraries/physics/src/PhysicsEntity.cpp @@ -11,7 +11,6 @@ #include "PhysicsEntity.h" -#include "PhysicsSimulation.h" #include "PlaneShape.h" #include "Shape.h" #include "ShapeCollider.h" @@ -22,15 +21,10 @@ PhysicsEntity::PhysicsEntity() : _rotation(), _boundingRadius(0.0f), _shapesAreDirty(true), - _enableShapes(false), - _simulation(NULL) { + _enableShapes(false) { } PhysicsEntity::~PhysicsEntity() { - if (_simulation) { - _simulation->removeEntity(this); - _simulation = NULL; - } } void PhysicsEntity::setTranslation(const glm::vec3& translation) { @@ -67,9 +61,6 @@ void PhysicsEntity::setEnableShapes(bool enable) { } void PhysicsEntity::clearShapes() { - if (_simulation) { - _simulation->removeShapes(this); - } for (int i = 0; i < _shapes.size(); ++i) { delete _shapes[i]; } @@ -178,24 +169,3 @@ bool PhysicsEntity::collisionsAreEnabled(int shapeIndexA, int shapeIndexB) const } return false; } - -void PhysicsEntity::disableCurrentSelfCollisions() { - CollisionList collisions(10); - int numShapes = _shapes.size(); - for (int i = 0; i < numShapes; ++i) { - const Shape* shape = _shapes.at(i); - if (!shape) { - continue; - } - for (int j = i+1; j < numShapes; ++j) { - if (!collisionsAreEnabled(i, j)) { - continue; - } - const Shape* otherShape = _shapes.at(j); - if (otherShape && ShapeCollider::collideShapes(shape, otherShape, collisions)) { - disableCollisions(i, j); - collisions.clear(); - } - } - } -} diff --git a/libraries/physics/src/PhysicsEntity.h b/libraries/physics/src/PhysicsEntity.h index 358c058551..f01f1d10a6 100644 --- a/libraries/physics/src/PhysicsEntity.h +++ b/libraries/physics/src/PhysicsEntity.h @@ -22,11 +22,6 @@ #include class Shape; -class PhysicsSimulation; - -// PhysicsEntity is the base class for anything that owns one or more Shapes that collide in a -// PhysicsSimulation. Each CollisionInfo generated by a PhysicsSimulation has back pointers to the -// two Shapes involved, and those Shapes may (optionally) have valid back pointers to their PhysicsEntity. class PhysicsEntity { @@ -51,8 +46,6 @@ public: virtual void clearShapes(); const QVector getShapes() const { return _shapes; } - PhysicsSimulation* getSimulation() const { return _simulation; } - bool findRayIntersection(RayIntersectionInfo& intersection) const; bool findCollisions(const QVector shapes, CollisionList& collisions); bool findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadius, CollisionList& collisions); @@ -61,8 +54,6 @@ public: void disableCollisions(int shapeIndexA, int shapeIndexB); bool collisionsAreEnabled(int shapeIndexA, int shapeIndexB) const; - void disableCurrentSelfCollisions(); - protected: glm::vec3 _translation; glm::quat _rotation; @@ -71,11 +62,6 @@ protected: bool _enableShapes; QVector _shapes; QSet _disabledCollisions; - -private: - // PhysicsSimulation is a friend so that it can set the protected _simulation backpointer - friend class PhysicsSimulation; - PhysicsSimulation* _simulation; }; #endif // hifi_PhysicsEntity_h diff --git a/libraries/physics/src/PhysicsSimulation.cpp b/libraries/physics/src/PhysicsSimulation.cpp deleted file mode 100644 index b92d9bec8f..0000000000 --- a/libraries/physics/src/PhysicsSimulation.cpp +++ /dev/null @@ -1,405 +0,0 @@ -// -// PhysicsSimulation.cpp -// libraries/physcis/src -// -// Created by Andrew Meadows 2014.06.06 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include -#include - -#include "PhysicsSimulation.h" -#include "PhysicsEntity.h" -#include "Ragdoll.h" -#include "Shape.h" -#include "ShapeCollider.h" - -int MAX_DOLLS_PER_SIMULATION = 16; -int MAX_ENTITIES_PER_SIMULATION = 64; -int MAX_COLLISIONS_PER_SIMULATION = 256; - - -PhysicsSimulation::PhysicsSimulation() : _translation(0.0f), _frameCount(0), _entity(NULL), _ragdoll(NULL), - _collisions(MAX_COLLISIONS_PER_SIMULATION) { -} - -PhysicsSimulation::~PhysicsSimulation() { - clear(); -} - -void PhysicsSimulation::clear() { - // entities have a backpointer to this simulator that must be cleaned up - int numEntities = _otherEntities.size(); - for (int i = 0; i < numEntities; ++i) { - _otherEntities[i]->_simulation = NULL; - } - _otherEntities.clear(); - if (_entity) { - _entity->_simulation = NULL; - } - - // but Ragdolls do not - _ragdoll = NULL; - _otherRagdolls.clear(); - - // contacts have backpointers to shapes so we clear them - _contacts.clear(); -} - -void PhysicsSimulation::setRagdoll(Ragdoll* ragdoll) { - if (_ragdoll != ragdoll) { - if (_ragdoll) { - _ragdoll->_simulation = NULL; - } - _ragdoll = ragdoll; - if (_ragdoll) { - assert(!(_ragdoll->_simulation)); - _ragdoll->_simulation = this; - } - } -} - -void PhysicsSimulation::setEntity(PhysicsEntity* entity) { - if (_entity != entity) { - if (_entity) { - assert(_entity->_simulation == this); - _entity->_simulation = NULL; - } - _entity = entity; - if (_entity) { - assert(!(_entity->_simulation)); - _entity->_simulation = this; - } - } -} - -bool PhysicsSimulation::addEntity(PhysicsEntity* entity) { - if (!entity) { - return false; - } - if (entity->_simulation == this) { - int numEntities = _otherEntities.size(); - for (int i = 0; i < numEntities; ++i) { - if (entity == _otherEntities.at(i)) { - // already in list - return true; - } - } - // belongs to some other simulation - return false; - } - int numEntities = _otherEntities.size(); - if (numEntities > MAX_ENTITIES_PER_SIMULATION) { - // list is full - return false; - } - // add to list - assert(!(entity->_simulation)); - entity->_simulation = this; - _otherEntities.push_back(entity); - return true; -} - -void PhysicsSimulation::removeEntity(PhysicsEntity* entity) { - if (!entity || !entity->_simulation || !(entity->_simulation == this)) { - return; - } - removeShapes(entity); - int numEntities = _otherEntities.size(); - for (int i = 0; i < numEntities; ++i) { - if (entity == _otherEntities.at(i)) { - if (i == numEntities - 1) { - // remove it - _otherEntities.pop_back(); - } else { - // swap the last for this one - PhysicsEntity* lastEntity = _otherEntities[numEntities - 1]; - _otherEntities.pop_back(); - _otherEntities[i] = lastEntity; - } - entity->_simulation = NULL; - break; - } - } -} - -void PhysicsSimulation::removeShapes(const PhysicsEntity* entity) { - // remove data structures with pointers to entity's shapes - QMap::iterator itr = _contacts.begin(); - while (itr != _contacts.end()) { - if (entity == itr.value().getShapeA()->getEntity() || entity == itr.value().getShapeB()->getEntity()) { - itr = _contacts.erase(itr); - } else { - ++itr; - } - } -} - -void PhysicsSimulation::removeShape(const Shape* shape) { - // remove data structures with pointers to shape - QMap::iterator itr = _contacts.begin(); - while (itr != _contacts.end()) { - if (shape == itr.value().getShapeA() || shape == itr.value().getShapeB()) { - itr = _contacts.erase(itr); - } else { - ++itr; - } - } -} - -const float OTHER_RAGDOLL_MASS_SCALE = 10.0f; - -bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { - if (!doll) { - return false; - } - int numDolls = _otherRagdolls.size(); - if (numDolls > MAX_DOLLS_PER_SIMULATION) { - // list is full - return false; - } - if (doll->_simulation == this) { - for (int i = 0; i < numDolls; ++i) { - if (doll == _otherRagdolls[i]) { - // already in list - return true; - } - } - } - // add to list - assert(!(doll->_simulation)); - doll->_simulation = this; - _otherRagdolls.push_back(doll); - - // set the massScale of otherRagdolls artificially high - doll->setMassScale(OTHER_RAGDOLL_MASS_SCALE); - return true; -} - -void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { - if (!doll || doll->_simulation != this) { - return; - } - int numDolls = _otherRagdolls.size(); - for (int i = 0; i < numDolls; ++i) { - if (doll == _otherRagdolls[i]) { - if (i == numDolls - 1) { - // remove it - _otherRagdolls.pop_back(); - } else { - // swap the last for this one - Ragdoll* lastDoll = _otherRagdolls[numDolls - 1]; - _otherRagdolls.pop_back(); - _otherRagdolls[i] = lastDoll; - } - doll->_simulation = NULL; - doll->setMassScale(1.0f); - break; - } - } -} - -void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec) { - ++_frameCount; - quint64 now = usecTimestampNow(); - quint64 startTime = now; - quint64 expiry = startTime + maxUsec; - - integrate(deltaTime); - enforceContacts(); - int numDolls = _otherRagdolls.size(); - { - PerformanceTimer perfTimer("enforce"); - if (_ragdoll) { - _ragdoll->enforceConstraints(); - } - for (int i = 0; i < numDolls; ++i) { - _otherRagdolls[i]->enforceConstraints(); - } - } - - bool collidedWithOtherRagdoll = false; - int iterations = 0; - float error = 0.0f; - do { - collidedWithOtherRagdoll = computeCollisions() || collidedWithOtherRagdoll; - updateContacts(); - resolveCollisions(); - - { // enforce constraints - PerformanceTimer perfTimer("enforce"); - if (_ragdoll) { - error = _ragdoll->enforceConstraints(); - } - for (int i = 0; i < numDolls; ++i) { - error = glm::max(error, _otherRagdolls[i]->enforceConstraints()); - } - } - applyContactFriction(); - ++iterations; - - now = usecTimestampNow(); - } while (_collisions.size() != 0 && (iterations < maxIterations) && (error > minError) && (now < expiry)); - - if (_ragdoll) { - // This is why _ragdoll is special and is not in the list of other ragdolls: - // The collisions may have moved the main ragdoll from the simulation center - // so we remove this offset (potentially storing it as movement of the Ragdoll owner) - _ragdoll->removeRootOffset(collidedWithOtherRagdoll); - } - - // also remove any offsets from the other ragdolls - for (int i = 0; i < numDolls; ++i) { - _otherRagdolls[i]->removeRootOffset(false); - } - pruneContacts(); -} - -bool PhysicsSimulation::findFloorRayIntersection(RayIntersectionInfo& intersection) const { - // only casts against otherEntities - bool hit = false; - int numEntities = _otherEntities.size(); - for (int i = 0; i < numEntities; ++i) { - const QVector otherShapes = _otherEntities.at(i)->getShapes(); - if (ShapeCollider::findRayIntersection(otherShapes, intersection)) { - hit = true; - } - } - return hit; -} - - -bool PhysicsSimulation::getShapeCollisions(const Shape* shape, CollisionList& collisions) const { - bool hit = false; - int numEntities = _otherEntities.size(); - for (int i = 0; i < numEntities; ++i) { - const QVector otherShapes = _otherEntities.at(i)->getShapes(); - if (ShapeCollider::collideShapeWithShapes(shape, otherShapes, 0, collisions)) { - hit = true; - } - } - return hit; -} - -void PhysicsSimulation::integrate(float deltaTime) { - PerformanceTimer perfTimer("integrate"); - int numEntities = _otherEntities.size(); - for (int i = 0; i < numEntities; ++i) { - _otherEntities[i]->stepForward(deltaTime); - } - if (_ragdoll) { - _ragdoll->stepForward(deltaTime); - } - int numDolls = _otherRagdolls.size(); - for (int i = 0; i < numDolls; ++i) { - _otherRagdolls[i]->stepForward(deltaTime); - } -} - -bool PhysicsSimulation::computeCollisions() { - PerformanceTimer perfTimer("collide"); - _collisions.clear(); - - const QVector shapes = _entity->getShapes(); - int numShapes = shapes.size(); - // collide main ragdoll with self - for (int i = 0; i < numShapes; ++i) { - const Shape* shape = shapes.at(i); - if (!shape) { - continue; - } - for (int j = i+1; j < numShapes; ++j) { - const Shape* otherShape = shapes.at(j); - if (otherShape && _entity->collisionsAreEnabled(i, j)) { - ShapeCollider::collideShapes(shape, otherShape, _collisions); - } - } - } - - // collide main ragdoll with others - bool otherCollisions = false; - int numEntities = _otherEntities.size(); - for (int i = 0; i < numEntities; ++i) { - const QVector otherShapes = _otherEntities.at(i)->getShapes(); - otherCollisions = ShapeCollider::collideShapesWithShapes(shapes, otherShapes, _collisions) || otherCollisions; - } - return otherCollisions; -} - -void PhysicsSimulation::resolveCollisions() { - PerformanceTimer perfTimer("resolve"); - // walk all collisions, accumulate movement on shapes, and build a list of affected shapes - QSet shapes; - int numCollisions = _collisions.size(); - for (int i = 0; i < numCollisions; ++i) { - CollisionInfo* collision = _collisions.getCollision(i); - collision->apply(); - // there is always a shapeA - shapes.insert(collision->getShapeA()); - // but need to check for valid shapeB - if (collision->_shapeB) { - shapes.insert(collision->getShapeB()); - } - } - // walk all affected shapes and apply accumulated movement - QSet::const_iterator shapeItr = shapes.constBegin(); - while (shapeItr != shapes.constEnd()) { - (*shapeItr)->applyAccumulatedDelta(); - ++shapeItr; - } -} - -void PhysicsSimulation::enforceContacts() { - PerformanceTimer perfTimer("contacts"); - QMap::iterator itr = _contacts.begin(); - while (itr != _contacts.end()) { - itr.value().enforce(); - ++itr; - } -} - -void PhysicsSimulation::applyContactFriction() { - PerformanceTimer perfTimer("contacts"); - QMap::iterator itr = _contacts.begin(); - while (itr != _contacts.end()) { - itr.value().applyFriction(); - ++itr; - } -} - -void PhysicsSimulation::updateContacts() { - PerformanceTimer perfTimer("contacts"); - int numCollisions = _collisions.size(); - for (int i = 0; i < numCollisions; ++i) { - CollisionInfo* collision = _collisions.getCollision(i); - quint64 key = collision->getShapePairKey(); - if (key == 0) { - continue; - } - QMap::iterator itr = _contacts.find(key); - if (itr == _contacts.end()) { - _contacts.insert(key, ContactPoint(*collision, _frameCount)); - } else { - itr.value().updateContact(*collision, _frameCount); - } - } -} - -const quint32 MAX_CONTACT_FRAME_LIFETIME = 2; - -void PhysicsSimulation::pruneContacts() { - QMap::iterator itr = _contacts.begin(); - while (itr != _contacts.end()) { - if (_frameCount - itr.value().getLastFrame() > MAX_CONTACT_FRAME_LIFETIME) { - itr = _contacts.erase(itr); - } else { - ++itr; - } - } -} diff --git a/libraries/physics/src/PhysicsSimulation.h b/libraries/physics/src/PhysicsSimulation.h deleted file mode 100644 index 404731e589..0000000000 --- a/libraries/physics/src/PhysicsSimulation.h +++ /dev/null @@ -1,92 +0,0 @@ -// -// PhysicsSimulation.h -// libraries/physcis/src -// -// Created by Andrew Meadows 2014.06.06 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_PhysicsSimulation_h -#define hifi_PhysicsSimulation_h - -#include -#include -#include - -#include "CollisionInfo.h" -#include "ContactPoint.h" -#include "RayIntersectionInfo.h" - -class PhysicsEntity; -class Ragdoll; - -class PhysicsSimulation { -public: - - PhysicsSimulation(); - ~PhysicsSimulation(); - - void clear(); - - void setTranslation(const glm::vec3& translation) { _translation = translation; } - const glm::vec3& getTranslation() const { return _translation; } - - void setRagdoll(Ragdoll* ragdoll); - void setEntity(PhysicsEntity* entity); - - /// \return true if entity was added to or is already in the list - bool addEntity(PhysicsEntity* entity); - - void removeEntity(PhysicsEntity* entity); - void removeShapes(const PhysicsEntity* entity); - void removeShape(const Shape* shape); - - /// \return true if doll was added to or is already in the list - bool addRagdoll(Ragdoll* doll); - - void removeRagdoll(Ragdoll* doll); - - /// \param minError constraint motion below this value is considered "close enough" - /// \param maxIterations max number of iterations before giving up - /// \param maxUsec max number of usec to spend enforcing constraints - /// \return distance of largest movement - void stepForward(float deltaTime, float minError, int maxIterations, quint64 maxUsec); - - /// \param intersection collision info about ray hit - /// \return true if ray hits any shape that doesn't belong to the main ragdoll/entity - bool findFloorRayIntersection(RayIntersectionInfo& hit) const; - - bool getShapeCollisions(const Shape* shape, CollisionList& collisions) const; - - void setupAvatarCollision(); - -protected: - void integrate(float deltaTime); - - /// \return true if main ragdoll collides with other avatar - bool computeCollisions(); - - void resolveCollisions(); - void enforceContacts(); - void applyContactFriction(); - void updateContacts(); - void pruneContacts(); - -private: - glm::vec3 _translation; // origin of simulation in world-frame - - quint32 _frameCount; - - PhysicsEntity* _entity; - Ragdoll* _ragdoll; - - QVector _otherRagdolls; - QVector _otherEntities; - CollisionList _collisions; - QMap _contacts; -}; - -#endif // hifi_PhysicsSimulation_h diff --git a/libraries/physics/src/Ragdoll.cpp b/libraries/physics/src/Ragdoll.cpp deleted file mode 100644 index 7936828025..0000000000 --- a/libraries/physics/src/Ragdoll.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// -// Ragdoll.cpp -// libraries/physics/src -// -// Created by Andrew Meadows 2014.05.30 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include // for EPSILON - -#include "Ragdoll.h" - -#include "Constraint.h" -#include "DistanceConstraint.h" -#include "FixedConstraint.h" -#include "PhysicsSimulation.h" - -Ragdoll::Ragdoll() : _massScale(1.0f), _translation(0.0f), _translationInSimulationFrame(0.0f), - _rootIndex(0), _accumulatedMovement(0.0f), _simulation(NULL) { -} - -Ragdoll::~Ragdoll() { - clearConstraintsAndPoints(); - if (_simulation) { - _simulation->removeRagdoll(this); - } -} - -void Ragdoll::stepForward(float deltaTime) { - if (_simulation) { - updateSimulationTransforms(_translation - _simulation->getTranslation(), _rotation); - } - int numPoints = _points.size(); - for (int i = _rootIndex; i < numPoints; ++i) { - _points[i].integrateForward(); - } -} - -void Ragdoll::clearConstraintsAndPoints() { - int numConstraints = _boneConstraints.size(); - for (int i = 0; i < numConstraints; ++i) { - delete _boneConstraints[i]; - } - _boneConstraints.clear(); - numConstraints = _fixedConstraints.size(); - for (int i = 0; i < numConstraints; ++i) { - delete _fixedConstraints[i]; - } - _fixedConstraints.clear(); - _points.clear(); -} - -float Ragdoll::enforceConstraints() { - float maxDistance = 0.0f; - // enforce the bone constraints first - int numConstraints = _boneConstraints.size(); - for (int i = 0; i < numConstraints; ++i) { - maxDistance = glm::max(maxDistance, _boneConstraints[i]->enforce()); - } - // enforce FixedConstraints second - numConstraints = _fixedConstraints.size(); - for (int i = 0; i < _fixedConstraints.size(); ++i) { - maxDistance = glm::max(maxDistance, _fixedConstraints[i]->enforce()); - } - return maxDistance; -} - -void Ragdoll::initTransform() { - _translation = glm::vec3(0.0f); - _rotation = glm::quat(); - _translationInSimulationFrame = glm::vec3(0.0f); - _rotationInSimulationFrame = glm::quat(); -} - -void Ragdoll::setTransform(const glm::vec3& translation, const glm::quat& rotation) { - if (translation != _translation) { - _translation = translation; - } - _rotation = rotation; -} - -void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation) { - const float EPSILON2 = EPSILON * EPSILON; - if (glm::distance2(translation, _translationInSimulationFrame) < EPSILON2 && - glm::abs(1.0f - glm::abs(glm::dot(rotation, _rotationInSimulationFrame))) < EPSILON2) { - // nothing to do - return; - } - - // compute linear and angular deltas - glm::vec3 deltaPosition = translation - _translationInSimulationFrame; - glm::quat deltaRotation = rotation * glm::inverse(_rotationInSimulationFrame); - - // apply the deltas to all ragdollPoints - int numPoints = _points.size(); - for (int i = _rootIndex; i < numPoints; ++i) { - _points[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame); - } - - // remember the current transform - _translationInSimulationFrame = translation; - _rotationInSimulationFrame = rotation; -} - -void Ragdoll::setMassScale(float scale) { - const float MIN_SCALE = 1.0e-2f; - const float MAX_SCALE = 1.0e6f; - scale = glm::clamp(glm::abs(scale), MIN_SCALE, MAX_SCALE); - if (scale != _massScale) { - float rescale = scale / _massScale; - int numPoints = _points.size(); - for (int i = _rootIndex; i < numPoints; ++i) { - _points[i].setMass(rescale * _points[i].getMass()); - } - _massScale = scale; - } -} - -void Ragdoll::removeRootOffset(bool accumulateMovement) { - const int numPoints = _points.size(); - if (numPoints > 0) { - // shift all points so that the root aligns with the the ragdoll's position in the simulation - glm::vec3 offset = _translationInSimulationFrame - _points[_rootIndex]._position; - float offsetLength = glm::length(offset); - if (offsetLength > EPSILON) { - for (int i = _rootIndex; i < numPoints; ++i) { - _points[i].shift(offset); - } - const float MIN_ROOT_OFFSET = 0.02f; - if (accumulateMovement && offsetLength > MIN_ROOT_OFFSET) { - _accumulatedMovement -= (1.0f - MIN_ROOT_OFFSET / offsetLength) * offset; - } - } - } -} - -glm::vec3 Ragdoll::getAndClearAccumulatedMovement() { - glm::vec3 movement = _accumulatedMovement; - _accumulatedMovement = glm::vec3(0.0f); - return movement; -} diff --git a/libraries/physics/src/Ragdoll.h b/libraries/physics/src/Ragdoll.h deleted file mode 100644 index ab81f165bd..0000000000 --- a/libraries/physics/src/Ragdoll.h +++ /dev/null @@ -1,91 +0,0 @@ -// -// Ragdoll.h -// libraries/physics/src -// -// Created by Andrew Meadows 2014.05.30 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_Ragdoll_h -#define hifi_Ragdoll_h - -#include -#include - -#include - -#include "VerletPoint.h" -//#include "PhysicsSimulation.h" - -class DistanceConstraint; -class FixedConstraint; -class PhysicsSimulation; - -// TODO: don't derive SkeletonModel from Ragdoll so we can clean up the Ragdoll API -// (==> won't need to worry about namespace conflicts between Entity and Ragdoll). - -class Ragdoll { -public: - - Ragdoll(); - virtual ~Ragdoll(); - - virtual void stepForward(float deltaTime); - - /// \return max distance of point movement - float enforceConstraints(); - - // both const and non-const getPoints() - const QVector& getPoints() const { return _points; } - QVector& getPoints() { return _points; } - - void initTransform(); - - /// set the translation and rotation of the Ragdoll and adjust all VerletPoints. - void setTransform(const glm::vec3& translation, const glm::quat& rotation); - - const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; } - - void setMassScale(float scale); - float getMassScale() const { return _massScale; } - - // the ragdoll's rootIndex (within a Model's joints) is not always zero so must be settable - void setRootIndex(int index) { _rootIndex = index; } - int getRootIndex() const { return _rootIndex; } - - void clearConstraintsAndPoints(); - virtual void initPoints() = 0; - virtual void buildConstraints() = 0; - - void removeRootOffset(bool accumulateMovement); - - glm::vec3 getAndClearAccumulatedMovement(); - -protected: - float _massScale; - glm::vec3 _translation; // world-frame - glm::quat _rotation; // world-frame - glm::vec3 _translationInSimulationFrame; - glm::quat _rotationInSimulationFrame; - int _rootIndex; - - QVector _points; - QVector _boneConstraints; - QVector _fixedConstraints; - - // The collisions are typically done in a simulation frame that is slaved to the center of one of the Ragdolls. - // To allow the Ragdoll to provide feedback of its own displacement we store it in _accumulatedMovement. - // The owner of the Ragdoll can harvest this displacement to update the rest of the object positions in the simulation. - glm::vec3 _accumulatedMovement; - -private: - void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation); - - friend class PhysicsSimulation; - PhysicsSimulation* _simulation; -}; - -#endif // hifi_Ragdoll_h diff --git a/libraries/physics/src/VerletCapsuleShape.cpp b/libraries/physics/src/VerletCapsuleShape.cpp deleted file mode 100644 index a04c36d56d..0000000000 --- a/libraries/physics/src/VerletCapsuleShape.cpp +++ /dev/null @@ -1,170 +0,0 @@ -// -// VerletCapsuleShape.cpp -// libraries/physics/src -// -// Created by Andrew Meadows on 2014.06.16 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include - -#include "VerletCapsuleShape.h" - -#include "VerletPoint.h" - -VerletCapsuleShape::VerletCapsuleShape(VerletPoint* startPoint, VerletPoint* endPoint) : - CapsuleShape(), _startPoint(startPoint), _endPoint(endPoint), _startLagrangeCoef(0.5f), _endLagrangeCoef(0.5f) { - assert(startPoint); - assert(endPoint); - _halfHeight = 0.5f * glm::distance(_startPoint->_position, _endPoint->_position); - updateBoundingRadius(); -} - -VerletCapsuleShape::VerletCapsuleShape(float radius, VerletPoint* startPoint, VerletPoint* endPoint) : - CapsuleShape(radius, 1.0f), _startPoint(startPoint), _endPoint(endPoint), - _startLagrangeCoef(0.5f), _endLagrangeCoef(0.5f) { - assert(startPoint); - assert(endPoint); - _halfHeight = 0.5f * glm::distance(_startPoint->_position, _endPoint->_position); - updateBoundingRadius(); -} - -const glm::quat& VerletCapsuleShape::getRotation() const { - // NOTE: The "rotation" of this shape must be computed on the fly, - // which makes this method MUCH more more expensive than you might expect. - glm::vec3 axis; - computeNormalizedAxis(axis); - VerletCapsuleShape* thisCapsule = const_cast(this); - thisCapsule->_rotation = computeNewRotation(axis); - return _rotation; -} - -void VerletCapsuleShape::setRotation(const glm::quat& rotation) { - // NOTE: this method will update the verlet points, which is probably not - // what you want to do. Only call this method if you know what you're doing. - - // update points such that they have the same center but a different axis - glm::vec3 center = getTranslation(); - float halfHeight = getHalfHeight(); - glm::vec3 axis = rotation * DEFAULT_CAPSULE_AXIS; - _startPoint->_position = center - halfHeight * axis; - _endPoint->_position = center + halfHeight * axis; -} - -void VerletCapsuleShape::setTranslation(const glm::vec3& position) { - // NOTE: this method will update the verlet points, which is probably not - // what you want to do. Only call this method if you know what you're doing. - - // update the points such that their center is at position - glm::vec3 movement = position - getTranslation(); - _startPoint->_position += movement; - _endPoint->_position += movement; -} - -const glm::vec3& VerletCapsuleShape::getTranslation() const { - // the "translation" of this shape must be computed on the fly - VerletCapsuleShape* thisCapsule = const_cast(this); - thisCapsule->_translation = 0.5f * (_startPoint->_position + _endPoint->_position); - return _translation; -} - -float VerletCapsuleShape::computeEffectiveMass(const glm::vec3& penetration, const glm::vec3& contactPoint) { - glm::vec3 startLeg = _startPoint->_position - contactPoint; - glm::vec3 endLeg = _endPoint->_position - contactPoint; - - // TODO: use fast approximate distance calculations here - float startLength = glm::length(startLeg); - float endlength = glm::length(endLeg); - - // The raw coefficient is proportional to the other leg's length multiplied by the dot-product - // of the penetration and this leg direction. We don't worry about the common penetration length - // because it is normalized out later. - float startCoef = glm::abs(glm::dot(startLeg, penetration)) * endlength / (startLength + EPSILON); - float endCoef = glm::abs(glm::dot(endLeg, penetration)) * startLength / (endlength + EPSILON); - - float maxCoef = glm::max(startCoef, endCoef); - if (maxCoef > EPSILON) { - // One of these coeficients will be 1.0, the other will be less --> - // one endpoint will move the full amount while the other will move less. - _startLagrangeCoef = startCoef / maxCoef; - _endLagrangeCoef = endCoef / maxCoef; - } else { - // The coefficients are the same --> the collision will move both equally - // as if the contact were at the center of mass. - _startLagrangeCoef = 1.0f; - _endLagrangeCoef = 1.0f; - } - // the effective mass is the weighted sum of the two endpoints - return _startLagrangeCoef * _startPoint->getMass() + _endLagrangeCoef * _endPoint->getMass(); -} - -void VerletCapsuleShape::accumulateDelta(float relativeMassFactor, const glm::vec3& penetration) { - assert(!glm::isnan(relativeMassFactor)); - _startPoint->accumulateDelta((relativeMassFactor * _startLagrangeCoef) * penetration); - _endPoint->accumulateDelta((relativeMassFactor * _endLagrangeCoef) * penetration); -} - -void VerletCapsuleShape::applyAccumulatedDelta() { - _startPoint->applyAccumulatedDelta(); - _endPoint->applyAccumulatedDelta(); -} - -void VerletCapsuleShape::getVerletPoints(QVector& points) { - points.push_back(_startPoint); - points.push_back(_endPoint); -} - -// virtual -float VerletCapsuleShape::getHalfHeight() const { - return 0.5f * glm::distance(_startPoint->_position, _endPoint->_position); -} - -// virtual -void VerletCapsuleShape::getStartPoint(glm::vec3& startPoint) const { - startPoint = _startPoint->_position; -} - -// virtual -void VerletCapsuleShape::getEndPoint(glm::vec3& endPoint) const { - endPoint = _endPoint->_position; -} - -// virtual -void VerletCapsuleShape::computeNormalizedAxis(glm::vec3& axis) const { - glm::vec3 unormalizedAxis = _endPoint->_position - _startPoint->_position; - float fullLength = glm::length(unormalizedAxis); - if (fullLength > EPSILON) { - axis = unormalizedAxis / fullLength; - } else { - // the axis is meaningless, but we fill it with a normalized direction - // just in case the calling context assumes it really is normalized. - axis = glm::vec3(0.0f, 1.0f, 0.0f); - } -} - -// virtual -void VerletCapsuleShape::setHalfHeight(float halfHeight) { - // push points along axis so they are 2*halfHeight apart - glm::vec3 center = getTranslation(); - glm::vec3 axis; - computeNormalizedAxis(axis); - _startPoint->_position = center - halfHeight * axis; - _endPoint->_position = center + halfHeight * axis; - _boundingRadius = _radius + halfHeight; -} - -// virtual -void VerletCapsuleShape::setRadiusAndHalfHeight(float radius, float halfHeight) { - _radius = radius; - setHalfHeight(halfHeight); -} - -// virtual -void VerletCapsuleShape::setEndPoints(const glm::vec3& startPoint, const glm::vec3& endPoint) { - _startPoint->_position = startPoint; - _endPoint->_position = endPoint; - updateBoundingRadius(); -} diff --git a/libraries/physics/src/VerletCapsuleShape.h b/libraries/physics/src/VerletCapsuleShape.h deleted file mode 100644 index 19afab2b61..0000000000 --- a/libraries/physics/src/VerletCapsuleShape.h +++ /dev/null @@ -1,84 +0,0 @@ -// -// VerletCapsuleShape.h -// libraries/physics/src -// -// Created by Andrew Meadows on 2014.06.16 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_VerletCapsuleShape_h -#define hifi_VerletCapsuleShape_h - -#include "CapsuleShape.h" - - -// The VerletCapsuleShape is similar to a regular CapsuleShape, except it keeps a pointer -// to its endpoints which are owned by some other data structure (a verlet simulation system). -// This makes it easier for the points to be moved around by constraints in the system -// as well as collisions with the shape, however it has some drawbacks: -// -// (1) The Shape::_translation and ::_rotation data members are not used (wasted) -// -// (2) A VerletShape doesn't own the points that it uses, so you must be careful not to -// leave dangling pointers around. -// -// (3) Some const methods of VerletCapsuleShape are much more expensive than you might think. -// For example getHalfHeight() and setHalfHeight() methods must do extra computation. In -// particular setRotation() is significantly more expensive than for the CapsuleShape. -// Not too expensive to use when setting up shapes, but you woudln't want to use it deep -// down in a hot simulation loop, such as when processing collision results. Best to -// just let the verlet simulation do its thing and not try to constantly force a rotation. - -class VerletPoint; - -class VerletCapsuleShape : public CapsuleShape { -public: - VerletCapsuleShape(VerletPoint* startPoint, VerletPoint* endPoint); - VerletCapsuleShape(float radius, VerletPoint* startPoint, VerletPoint* endPoint); - - // virtual overrides from Shape - const glm::quat& getRotation() const; - void setRotation(const glm::quat& rotation); - void setTranslation(const glm::vec3& position); - const glm::vec3& getTranslation() const; - float computeEffectiveMass(const glm::vec3& penetration, const glm::vec3& contactPoint); - void accumulateDelta(float relativeMassFactor, const glm::vec3& penetration); - void applyAccumulatedDelta(); - virtual void getVerletPoints(QVector& points); - - //float getRadius() const { return _radius; } - virtual float getHalfHeight() const; - - /// \param[out] startPoint is the center of start cap - void getStartPoint(glm::vec3& startPoint) const; - - /// \param[out] endPoint is the center of the end cap - void getEndPoint(glm::vec3& endPoint) const; - - /// \param[out] axis is a normalized vector that points from start to end - void computeNormalizedAxis(glm::vec3& axis) const; - - //void setRadius(float radius); - void setHalfHeight(float halfHeight); - void setRadiusAndHalfHeight(float radius, float halfHeight); - void setEndPoints(const glm::vec3& startPoint, const glm::vec3& endPoint); - - //void assignEndPoints(glm::vec3* startPoint, glm::vec3* endPoint); - -protected: - // NOTE: VerletCapsuleShape does NOT own the data in its points. - VerletPoint* _startPoint; - VerletPoint* _endPoint; - - // The LagrangeCoef's are numerical weights for distributing collision movement - // between the relevant VerletPoints associated with this shape. They are functions - // of the movement parameters and are computed (and cached) in computeEffectiveMass() - // and then used in the subsequent accumulateDelta(). - float _startLagrangeCoef; - float _endLagrangeCoef; -}; - -#endif // hifi_VerletCapsuleShape_h diff --git a/libraries/physics/src/VerletPoint.cpp b/libraries/physics/src/VerletPoint.cpp deleted file mode 100644 index 895f3be8b2..0000000000 --- a/libraries/physics/src/VerletPoint.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// -// VerletPoint.cpp -// libraries/physics/src -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "VerletPoint.h" - -const float INTEGRATION_FRICTION_FACTOR = 0.6f; - -void VerletPoint::integrateForward() { - glm::vec3 oldPosition = _position; - _position += INTEGRATION_FRICTION_FACTOR * (_position - _lastPosition); - _lastPosition = oldPosition; -} - -void VerletPoint::accumulateDelta(const glm::vec3& delta) { - _accumulatedDelta += delta; - ++_numDeltas; -} - -void VerletPoint::applyAccumulatedDelta() { - if (_numDeltas > 0) { - _position += _accumulatedDelta / (float)_numDeltas; - _accumulatedDelta = glm::vec3(0.0f); - _numDeltas = 0; - } -} - -void VerletPoint::move(const glm::vec3& deltaPosition, const glm::quat& deltaRotation, const glm::vec3& oldPivot) { - glm::vec3 arm = _position - oldPivot; - _position += deltaPosition + (deltaRotation * arm - arm); - arm = _lastPosition - oldPivot; - _lastPosition += deltaPosition + (deltaRotation * arm - arm); -} - -void VerletPoint::shift(const glm::vec3& deltaPosition) { - _position += deltaPosition; - _lastPosition += deltaPosition; -} - -void VerletPoint::setMass(float mass) { - const float MIN_MASS = 1.0e-6f; - const float MAX_MASS = 1.0e18f; - if (glm::isnan(mass)) { - mass = MIN_MASS; - } - _mass = glm::clamp(glm::abs(mass), MIN_MASS, MAX_MASS); -} diff --git a/libraries/physics/src/VerletPoint.h b/libraries/physics/src/VerletPoint.h deleted file mode 100644 index d80698c9e2..0000000000 --- a/libraries/physics/src/VerletPoint.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// VerletPoint.h -// libraries/physics/src -// -// Created by Andrew Meadows 2014.07.24 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_VerletPoint_h -#define hifi_VerletPoint_h - -#include -#include - - -class VerletPoint { -public: - VerletPoint() : _position(0.0f), _lastPosition(0.0f), _mass(1.0f), _accumulatedDelta(0.0f), _numDeltas(0) {} - - void initPosition(const glm::vec3& position) { _position = position; _lastPosition = position; } - void integrateForward(); - void accumulateDelta(const glm::vec3& delta); - void applyAccumulatedDelta(); - void move(const glm::vec3& deltaPosition, const glm::quat& deltaRotation, const glm::vec3& oldPivot); - void shift(const glm::vec3& deltaPosition); - - void setMass(float mass); - float getMass() const { return _mass; } - - glm::vec3 _position; - glm::vec3 _lastPosition; - -private: - float _mass; - glm::vec3 _accumulatedDelta; - int _numDeltas; -}; - -#endif // hifi_VerletPoint_h diff --git a/libraries/physics/src/VerletSphereShape.cpp b/libraries/physics/src/VerletSphereShape.cpp deleted file mode 100644 index 83dcbd9a58..0000000000 --- a/libraries/physics/src/VerletSphereShape.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// -// VerletSphereShape.cpp -// libraries/physics/src -// -// Created by Andrew Meadows on 2014.06.16 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "VerletSphereShape.h" - -#include "Ragdoll.h" // for VerletPoint - -VerletSphereShape::VerletSphereShape(VerletPoint* centerPoint) : SphereShape() { - assert(centerPoint); - _point = centerPoint; -} - -VerletSphereShape::VerletSphereShape(float radius, VerletPoint* centerPoint) : SphereShape(radius) { - assert(centerPoint); - _point = centerPoint; -} - -// virtual from Shape class -void VerletSphereShape::setTranslation(const glm::vec3& position) { - _point->_position = position; - _point->_lastPosition = position; -} - -// virtual from Shape class -const glm::vec3& VerletSphereShape::getTranslation() const { - return _point->_position; -} - -// virtual -float VerletSphereShape::computeEffectiveMass(const glm::vec3& penetration, const glm::vec3& contactPoint) { - return _point->getMass(); -} - -// virtual -void VerletSphereShape::accumulateDelta(float relativeMassFactor, const glm::vec3& penetration) { - _point->accumulateDelta(relativeMassFactor * penetration); -} - -// virtual -void VerletSphereShape::applyAccumulatedDelta() { - _point->applyAccumulatedDelta(); -} - -void VerletSphereShape::getVerletPoints(QVector& points) { - points.push_back(_point); -} diff --git a/libraries/physics/src/VerletSphereShape.h b/libraries/physics/src/VerletSphereShape.h deleted file mode 100644 index 596f4a517b..0000000000 --- a/libraries/physics/src/VerletSphereShape.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// VerletSphereShape.h -// libraries/physics/src -// -// Created by Andrew Meadows on 2014.06.16 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_VerletSphereShape_h -#define hifi_VerletSphereShape_h - -#include "SphereShape.h" - -// The VerletSphereShape is similar to a regular SphereShape, except it keeps a pointer -// to its center which is owned by some other data structure (a verlet simulation system). -// This makes it easier for the points to be moved around by constraints in the system -// as well as collisions with the shape, however it has some drawbacks: -// -// (1) The Shape::_translation data member is not used (wasted) -// -// (2) A VerletShape doesn't own the points that it uses, so you must be careful not to -// leave dangling pointers around. - -class VerletPoint; - -class VerletSphereShape : public SphereShape { -public: - VerletSphereShape(VerletPoint* point); - - VerletSphereShape(float radius, VerletPoint* centerPoint); - - // virtual overrides from Shape - void setTranslation(const glm::vec3& position); - const glm::vec3& getTranslation() const; - float computeEffectiveMass(const glm::vec3& penetration, const glm::vec3& contactPoint); - void accumulateDelta(float relativeMassFactor, const glm::vec3& penetration); - void applyAccumulatedDelta(); - void getVerletPoints(QVector& points); - - -protected: - // NOTE: VerletSphereShape does NOT own its _point - VerletPoint* _point; -}; - -#endif // hifi_VerletSphereShape_h diff --git a/libraries/shared/src/Shape.h b/libraries/shared/src/Shape.h index dd318c2776..048b8d7257 100644 --- a/libraries/shared/src/Shape.h +++ b/libraries/shared/src/Shape.h @@ -21,7 +21,6 @@ #include "RayIntersectionInfo.h" class PhysicsEntity; -class VerletPoint; const float MAX_SHAPE_MASS = 1.0e18f; // something less than sqrt(FLT_MAX) @@ -87,8 +86,6 @@ public: /// \return volume of shape in cubic meters virtual float getVolume() const { return 1.0; } - virtual void getVerletPoints(QVector& points) {} - virtual QDebug& dumpToDebug(QDebug& debugConext) const; protected: diff --git a/tests/physics/src/VerletShapeTests.cpp b/tests/physics/src/VerletShapeTests.cpp deleted file mode 100644 index c075fa9f85..0000000000 --- a/tests/physics/src/VerletShapeTests.cpp +++ /dev/null @@ -1,766 +0,0 @@ -// -// VerletShapeTests.cpp -// tests/physics/src -// -// Created by Andrew Meadows on 02/21/2014. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -//#include -#include -#include - -#include -#include - -#include -#include // for VerletPoint -#include -#include -#include -#include -#include - -#include "VerletShapeTests.h" - -const glm::vec3 origin(0.0f); -static const glm::vec3 xAxis(1.0f, 0.0f, 0.0f); -static const glm::vec3 yAxis(0.0f, 1.0f, 0.0f); -static const glm::vec3 zAxis(0.0f, 0.0f, 1.0f); - -void VerletShapeTests::setSpherePosition() { - float radius = 1.0f; - glm::vec3 offset(1.23f, 4.56f, 7.89f); - VerletPoint point; - VerletSphereShape sphere(radius, &point); - - point._position = glm::vec3(0.0f); - float d = glm::distance(glm::vec3(0.0f), sphere.getTranslation()); - if (d != 0.0f) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should be at origin" << std::endl; - } - - point._position = offset; - d = glm::distance(glm::vec3(0.0f), sphere.getTranslation()); - if (d != glm::length(offset)) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should be at offset" << std::endl; - } -} - -void VerletShapeTests::sphereMissesSphere() { - // non-overlapping spheres of unequal size - - float radiusA = 7.0f; - float radiusB = 3.0f; - float alpha = 1.2f; - float beta = 1.3f; - glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); - float offsetDistance = alpha * radiusA + beta * radiusB; - - // create points for the sphere centers - VerletPoint points[2]; - - // give pointers to the spheres - VerletSphereShape sphereA(radiusA, (points + 0)); - VerletSphereShape sphereB(radiusB, (points + 1)); - - // set the positions of the spheres by slamming the points directly - points[0]._position = origin; - points[1]._position = offsetDistance * offsetDirection; - - CollisionList collisions(16); - - // collide A to B... - { - bool touching = ShapeCollider::collideShapes(&sphereA, &sphereB, collisions); - if (touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should NOT touch" << std::endl; - } - } - - // collide B to A... - { - bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions); - if (touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should NOT touch" << std::endl; - } - } - - // also test shapeShape - { - bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions); - if (touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should NOT touch" << std::endl; - } - } - - if (collisions.size() > 0) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected empty collision list but size is " << collisions.size() << std::endl; - } -} - -void VerletShapeTests::sphereTouchesSphere() { - // overlapping spheres of unequal size - float radiusA = 7.0f; - float radiusB = 3.0f; - float alpha = 0.2f; - float beta = 0.3f; - glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f)); - float offsetDistance = alpha * radiusA + beta * radiusB; - float expectedPenetrationDistance = (1.0f - alpha) * radiusA + (1.0f - beta) * radiusB; - glm::vec3 expectedPenetration = expectedPenetrationDistance * offsetDirection; - - // create two points for the sphere centers - VerletPoint points[2]; - - // give pointers to the spheres - VerletSphereShape sphereA(radiusA, points+0); - VerletSphereShape sphereB(radiusB, points+1); - - // set the positions of the spheres by slamming the points directly - points[0]._position = origin; - points[1]._position = offsetDistance * offsetDirection; - - CollisionList collisions(16); - int numCollisions = 0; - - // collide A to B... - { - bool touching = ShapeCollider::collideShapes(&sphereA, &sphereB, collisions); - if (!touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should touch" << std::endl; - } else { - ++numCollisions; - } - - // verify state of collisions - if (numCollisions != collisions.size()) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected collisions size of " << numCollisions << " but actual size is " << collisions.size() - << std::endl; - } - CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - if (!collision) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: null collision" << std::endl; - } - - // penetration points from sphereA into sphereB - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - // contactPoint is on surface of sphereA - glm::vec3 AtoB = sphereB.getTranslation() - sphereA.getTranslation(); - glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * glm::normalize(AtoB); - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - } - - // collide B to A... - { - bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions); - if (!touching) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphereA and sphereB should touch" << std::endl; - } else { - ++numCollisions; - } - - // penetration points from sphereA into sphereB - CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - float inaccuracy = glm::length(collision->_penetration + expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - // contactPoint is on surface of sphereA - glm::vec3 BtoA = sphereA.getTranslation() - sphereB.getTranslation(); - glm::vec3 expectedContactPoint = sphereB.getTranslation() + radiusB * glm::normalize(BtoA); - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - } -} - -void VerletShapeTests::sphereMissesCapsule() { - // non-overlapping sphere and capsule - float radiusA = 1.5f; - float radiusB = 2.3f; - float totalRadius = radiusA + radiusB; - float halfHeightB = 1.7f; - float axialOffset = totalRadius + 1.1f * halfHeightB; - float radialOffset = 1.2f * radiusA + 1.3f * radiusB; - - // create points for the sphere + capsule - VerletPoint points[3]; - for (int i = 0; i < 3; ++i) { - points[i]._position = glm::vec3(0.0f); - } - - // give the points to the shapes - VerletSphereShape sphereA(radiusA, points); - VerletCapsuleShape capsuleB(radiusB, points+1, points+2); - capsuleB.setHalfHeight(halfHeightB); - - // give the capsule some arbitrary transform - float angle = 37.8f; - glm::vec3 axis = glm::normalize( glm::vec3(-7.0f, 2.8f, 9.3f) ); - glm::quat rotation = glm::angleAxis(angle, axis); - glm::vec3 translation(15.1f, -27.1f, -38.6f); - capsuleB.setRotation(rotation); - capsuleB.setTranslation(translation); - - CollisionList collisions(16); - - // walk sphereA along the local yAxis next to, but not touching, capsuleB - glm::vec3 localStartPosition(radialOffset, axialOffset, 0.0f); - int numberOfSteps = 10; - float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1); - for (int i = 0; i < numberOfSteps; ++i) { - // translate sphereA into world-frame - glm::vec3 localPosition = localStartPosition + ((float)i * delta) * yAxis; - sphereA.setTranslation(rotation * localPosition + translation); - - // sphereA agains capsuleB - if (ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphere and capsule should NOT touch" << std::endl; - } - - // capsuleB against sphereA - if (ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphere and capsule should NOT touch" << std::endl; - } - } - - if (collisions.size() > 0) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected empty collision list but size is " << collisions.size() << std::endl; - } -} - -void VerletShapeTests::sphereTouchesCapsule() { - // overlapping sphere and capsule - float radiusA = 2.0f; - float radiusB = 1.0f; - float totalRadius = radiusA + radiusB; - float halfHeightB = 2.0f; - float alpha = 0.5f; - float beta = 0.5f; - float radialOffset = alpha * radiusA + beta * radiusB; - - // create points for the sphere + capsule - VerletPoint points[3]; - for (int i = 0; i < 3; ++i) { - points[i]._position = glm::vec3(0.0f); - } - - // give the points to the shapes - VerletSphereShape sphereA(radiusA, points); - VerletCapsuleShape capsuleB(radiusB, points+1, points+2); - capsuleB.setHalfHeight(halfHeightB); - - CollisionList collisions(16); - int numCollisions = 0; - - { // sphereA collides with capsuleB's cylindrical wall - sphereA.setTranslation(radialOffset * xAxis); - - if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphere and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - - // penetration points from sphereA into capsuleB - CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - glm::vec3 expectedPenetration = (radialOffset - totalRadius) * xAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - // contactPoint is on surface of sphereA - glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * xAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - - // capsuleB collides with sphereA - if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and sphere should touch" << std::endl; - } else { - ++numCollisions; - } - - // penetration points from sphereA into capsuleB - collision = collisions.getCollision(numCollisions - 1); - expectedPenetration = - (radialOffset - totalRadius) * xAxis; - if (collision->_shapeA == &sphereA) { - // the ShapeCollider swapped the order of the shapes - expectedPenetration *= -1.0f; - } - inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - // contactPoint is on surface of capsuleB - glm::vec3 BtoA = sphereA.getTranslation() - capsuleB.getTranslation(); - glm::vec3 closestApproach = capsuleB.getTranslation() + glm::dot(BtoA, yAxis) * yAxis; - expectedContactPoint = closestApproach + radiusB * glm::normalize(BtoA - closestApproach); - if (collision->_shapeA == &sphereA) { - // the ShapeCollider swapped the order of the shapes - closestApproach = sphereA.getTranslation() - glm::dot(BtoA, yAxis) * yAxis; - expectedContactPoint = closestApproach - radiusB * glm::normalize(BtoA - closestApproach); - } - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - } - { // sphereA hits end cap at axis - glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; - sphereA.setTranslation(axialOffset); - - if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphere and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - - // penetration points from sphereA into capsuleB - CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - // contactPoint is on surface of sphereA - glm::vec3 expectedContactPoint = sphereA.getTranslation() - radiusA * yAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - - // capsuleB collides with sphereA - if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and sphere should touch" << std::endl; - } else { - ++numCollisions; - } - - // penetration points from sphereA into capsuleB - collision = collisions.getCollision(numCollisions - 1); - expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; - if (collision->_shapeA == &sphereA) { - // the ShapeCollider swapped the order of the shapes - expectedPenetration *= -1.0f; - } - inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - // contactPoint is on surface of capsuleB - glm::vec3 endPoint; - capsuleB.getEndPoint(endPoint); - expectedContactPoint = endPoint + radiusB * yAxis; - if (collision->_shapeA == &sphereA) { - // the ShapeCollider swapped the order of the shapes - expectedContactPoint = axialOffset - radiusA * yAxis; - } - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - } - { // sphereA hits start cap at axis - glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis; - sphereA.setTranslation(axialOffset); - - if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: sphere and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - - // penetration points from sphereA into capsuleB - CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - // contactPoint is on surface of sphereA - glm::vec3 expectedContactPoint = sphereA.getTranslation() + radiusA * yAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - - // capsuleB collides with sphereA - if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and sphere should touch" << std::endl; - } else { - ++numCollisions; - } - - // penetration points from sphereA into capsuleB - collision = collisions.getCollision(numCollisions - 1); - expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis; - if (collision->_shapeA == &sphereA) { - // the ShapeCollider swapped the order of the shapes - expectedPenetration *= -1.0f; - } - inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - // contactPoint is on surface of capsuleB - glm::vec3 startPoint; - capsuleB.getStartPoint(startPoint); - expectedContactPoint = startPoint - radiusB * yAxis; - if (collision->_shapeA == &sphereA) { - // the ShapeCollider swapped the order of the shapes - expectedContactPoint = axialOffset + radiusA * yAxis; - } - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - } - if (collisions.size() != numCollisions) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected " << numCollisions << " collisions but actual number is " << collisions.size() - << std::endl; - } -} - -void VerletShapeTests::capsuleMissesCapsule() { - // non-overlapping capsules - float radiusA = 2.0f; - float halfHeightA = 3.0f; - float radiusB = 3.0f; - float halfHeightB = 4.0f; - - float totalRadius = radiusA + radiusB; - float totalHalfLength = totalRadius + halfHeightA + halfHeightB; - - // create points for the shapes - VerletPoint points[4]; - for (int i = 0; i < 4; ++i) { - points[i]._position = glm::vec3(0.0f); - } - - // give the points to the shapes - VerletCapsuleShape capsuleA(radiusA, points+0, points+1); - VerletCapsuleShape capsuleB(radiusB, points+2, points+3); - capsuleA.setHalfHeight(halfHeightA); - capsuleA.setHalfHeight(halfHeightB); - - CollisionList collisions(16); - - // side by side - capsuleB.setTranslation((1.01f * totalRadius) * xAxis); - if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } - if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } - - // end to end - capsuleB.setTranslation((1.01f * totalHalfLength) * xAxis); - if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } - if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } - - // rotate B and move it to the side - glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); - capsuleB.setRotation(rotation); - capsuleB.setTranslation((1.01f * (totalRadius + capsuleB.getHalfHeight())) * xAxis); - if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } - if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should NOT touch" << std::endl; - } - - if (collisions.size() > 0) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: expected empty collision list but size is " << collisions.size() << std::endl; - } -} - -void VerletShapeTests::capsuleTouchesCapsule() { - // overlapping capsules - float radiusA = 2.0f; - float halfHeightA = 3.0f; - float radiusB = 3.0f; - float halfHeightB = 4.0f; - - float totalRadius = radiusA + radiusB; - float totalHalfLength = totalRadius + halfHeightA + halfHeightB; - - // create points for the shapes - VerletPoint points[4]; - for (int i = 0; i < 4; ++i) { - points[i]._position = glm::vec3(0.0f); - } - - // give the points to the shapes - VerletCapsuleShape capsuleA(radiusA, points+0, points+1); - VerletCapsuleShape capsuleB(radiusB, points+2, points+3); - capsuleA.setHalfHeight(halfHeightA); - capsuleB.setHalfHeight(halfHeightB); - - CollisionList collisions(16); - int numCollisions = 0; - - { // side by side - capsuleB.setTranslation((0.99f * totalRadius) * xAxis); - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - } - - { // end to end - capsuleB.setTranslation((0.99f * totalHalfLength) * yAxis); - - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - } - - { // rotate B and move it to the side - glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); - capsuleB.setRotation(rotation); - capsuleB.setTranslation((0.99f * (totalRadius + capsuleB.getHalfHeight())) * xAxis); - - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - } - - { // again, but this time check collision details - float overlap = 0.1f; - glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); - capsuleB.setRotation(rotation); - glm::vec3 positionB = ((totalRadius + capsuleB.getHalfHeight()) - overlap) * xAxis; - capsuleB.setTranslation(positionB); - - // capsuleA vs capsuleB - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - - CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - glm::vec3 expectedPenetration = overlap * xAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * xAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - - // capsuleB vs capsuleA - if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - - collision = collisions.getCollision(numCollisions - 1); - expectedPenetration = - overlap * xAxis; - inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - expectedContactPoint = capsuleB.getTranslation() - (radiusB + halfHeightB) * xAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - } - - { // collide cylinder wall against cylinder wall - float overlap = 0.137f; - float shift = 0.317f * halfHeightA; - glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis); - capsuleB.setRotation(rotation); - glm::vec3 positionB = (totalRadius - overlap) * zAxis + shift * yAxis; - capsuleB.setTranslation(positionB); - - // capsuleA vs capsuleB - if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions)) - { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: capsule and capsule should touch" << std::endl; - } else { - ++numCollisions; - } - - CollisionInfo* collision = collisions.getCollision(numCollisions - 1); - glm::vec3 expectedPenetration = overlap * zAxis; - float inaccuracy = glm::length(collision->_penetration - expectedPenetration); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad penetration: expected = " << expectedPenetration - << " actual = " << collision->_penetration << std::endl; - } - - glm::vec3 expectedContactPoint = capsuleA.getTranslation() + radiusA * zAxis + shift * yAxis; - inaccuracy = glm::length(collision->_contactPoint - expectedContactPoint); - if (fabs(inaccuracy) > EPSILON) { - std::cout << __FILE__ << ":" << __LINE__ - << " ERROR: bad contactPoint: expected = " << expectedContactPoint - << " actual = " << collision->_contactPoint << std::endl; - } - } -} - -void VerletShapeTests::runAllTests() { - ShapeCollider::initDispatchTable(); - - setSpherePosition(); - sphereMissesSphere(); - sphereTouchesSphere(); - - sphereMissesCapsule(); - sphereTouchesCapsule(); - - capsuleMissesCapsule(); - capsuleTouchesCapsule(); -} diff --git a/tests/physics/src/VerletShapeTests.h b/tests/physics/src/VerletShapeTests.h deleted file mode 100644 index 36e2fe0cbd..0000000000 --- a/tests/physics/src/VerletShapeTests.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// VerletShapeTests.h -// tests/physics/src -// -// Created by Andrew Meadows on 2014.06.18 -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_VerletShapeTests_h -#define hifi_VerletShapeTests_h - -namespace VerletShapeTests { - void setSpherePosition(); - - void sphereMissesSphere(); - void sphereTouchesSphere(); - - void sphereMissesCapsule(); - void sphereTouchesCapsule(); - - void capsuleMissesCapsule(); - void capsuleTouchesCapsule(); - - void runAllTests(); -} - -#endif // hifi_VerletShapeTests_h diff --git a/tests/physics/src/main.cpp b/tests/physics/src/main.cpp index e7dae7aca5..0f35ed5002 100644 --- a/tests/physics/src/main.cpp +++ b/tests/physics/src/main.cpp @@ -9,7 +9,6 @@ // #include "ShapeColliderTests.h" -#include "VerletShapeTests.h" #include "ShapeInfoTests.h" #include "ShapeManagerTests.h" #include "BulletUtilTests.h" @@ -17,7 +16,6 @@ int main(int argc, char** argv) { ShapeColliderTests::runAllTests(); - VerletShapeTests::runAllTests(); ShapeInfoTests::runAllTests(); ShapeManagerTests::runAllTests(); BulletUtilTests::runAllTests(); From 1904e5e209346aa1d4918f3a8d73d63f8756149d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 11 Mar 2015 16:17:44 -0700 Subject: [PATCH 23/26] Make look.js the default look script and remove the old scripts --- examples/defaultScripts.js | 3 +- examples/lookWithMouse.js | 88 ---------------------------------- examples/lookWithTouch.js | 96 -------------------------------------- 3 files changed, 1 insertion(+), 186 deletions(-) delete mode 100644 examples/lookWithMouse.js delete mode 100644 examples/lookWithTouch.js diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index d4efad9ee5..6b57bf18dd 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -9,7 +9,6 @@ // Script.load("progress.js"); -Script.load("lookWithTouch.js"); Script.load("editEntities.js"); Script.load("selectAudioDevice.js"); Script.load("controllers/hydra/hydraMove.js"); @@ -17,5 +16,5 @@ Script.load("headMove.js"); Script.load("inspect.js"); Script.load("lobby.js"); Script.load("notifications.js"); -Script.load("lookWithMouse.js"); +Script.load("look.js"); Script.load("users.js"); diff --git a/examples/lookWithMouse.js b/examples/lookWithMouse.js deleted file mode 100644 index 470a56bd63..0000000000 --- a/examples/lookWithMouse.js +++ /dev/null @@ -1,88 +0,0 @@ -// -// lookWithMouse.js -// examples -// -// Created by Brad Hefta-Gaub on 1/28/14. -// Copyright 2014 High Fidelity, Inc. -// -// This is an example script that demonstrates use of the Controller class -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var alwaysLook = false; // if you want the mouse look to happen only when you click, change this to false -var isMouseDown = false; -var lastX = 0; -var lastY = 0; -var yawFromMouse = 0; -var pitchFromMouse = 0; -var wantDebugging = false; - -function mousePressEvent(event) { - if (wantDebugging) { - print("mousePressEvent event.x,y=" + event.x + ", " + event.y); - } - isMouseDown = true; - lastX = event.x; - lastY = event.y; -} - -function mouseReleaseEvent(event) { - if (wantDebugging) { - print("mouseReleaseEvent event.x,y=" + event.x + ", " + event.y); - } - isMouseDown = false; -} - -function mouseMoveEvent(event) { - if (wantDebugging) { - print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y); - } - - if (alwaysLook || isMouseDown) { - var MOUSE_YAW_SCALE = -0.25; - var MOUSE_PITCH_SCALE = -12.5; - var FIXED_MOUSE_TIMESTEP = 0.016; - yawFromMouse += ((event.x - lastX) * MOUSE_YAW_SCALE * FIXED_MOUSE_TIMESTEP); - pitchFromMouse += ((event.y - lastY) * MOUSE_PITCH_SCALE * FIXED_MOUSE_TIMESTEP); - lastX = event.x; - lastY = event.y; - } -} - -function update(deltaTime) { - if (wantDebugging) { - print("update()..."); - } - // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromVec3Radians( { x: 0, y: yawFromMouse, z: 0 } )); - if (wantDebugging) { - print("changing orientation" - + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," - + MyAvatar.orientation.z + "," + MyAvatar.orientation.w - + " newOrientation="+newOrientation.x + "," + newOrientation.y + "," + newOrientation.z + "," + newOrientation.w); - } - MyAvatar.orientation = newOrientation; - yawFromMouse = 0; - - // apply pitch from mouse - var newPitch = MyAvatar.headPitch + pitchFromMouse; - if (wantDebugging) { - print("changing pitch [old]MyAvatar.headPitch="+MyAvatar.headPitch+ " newPitch="+newPitch); - } - MyAvatar.headPitch = newPitch; - pitchFromMouse = 0; -} - -// Map the mouse events to our functions -Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseMoveEvent.connect(mouseMoveEvent); -Controller.mouseReleaseEvent.connect(mouseReleaseEvent); - -MyAvatar.bodyYaw = 0; -MyAvatar.bodyPitch = 0; -MyAvatar.bodyRoll = 0; - -// would be nice to change to update -Script.update.connect(update); diff --git a/examples/lookWithTouch.js b/examples/lookWithTouch.js deleted file mode 100644 index e9e7b0735a..0000000000 --- a/examples/lookWithTouch.js +++ /dev/null @@ -1,96 +0,0 @@ -// -// lookWithTouch.js -// examples -// -// Created by Brad Hefta-Gaub on 1/28/14. -// Copyright 2014 High Fidelity, Inc. -// -// This is an example script that demonstrates use of the Controller class -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var startedTouching = false; -var lastX = 0; -var lastY = 0; -var yawFromMouse = 0; -var pitchFromMouse = 0; -var wantDebugging = false; - -function touchBeginEvent(event) { - if (wantDebugging) { - print("touchBeginEvent event.x,y=" + event.x + ", " + event.y); - } - lastX = event.x; - lastY = event.y; - startedTouching = true; -} - -function touchEndEvent(event) { - if (wantDebugging) { - print("touchEndEvent event.x,y=" + event.x + ", " + event.y); - } - startedTouching = false; -} - -function touchUpdateEvent(event) { - if (wantDebugging) { - print("touchUpdateEvent event.x,y=" + event.x + ", " + event.y); - } - - if (!startedTouching) { - // handle Qt 5.4.x bug where we get touch update without a touch begin event - startedTouching = true; - lastX = event.x; - lastY = event.y; - } - - var MOUSE_YAW_SCALE = -0.25; - var MOUSE_PITCH_SCALE = -12.5; - var FIXED_MOUSE_TIMESTEP = 0.016; - yawFromMouse += ((event.x - lastX) * MOUSE_YAW_SCALE * FIXED_MOUSE_TIMESTEP); - pitchFromMouse += ((event.y - lastY) * MOUSE_PITCH_SCALE * FIXED_MOUSE_TIMESTEP); - lastX = event.x; - lastY = event.y; -} - -function update(deltaTime) { - if (startedTouching) { - // rotate body yaw for yaw received from mouse - var newOrientation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollRadians(0, yawFromMouse, 0)); - if (wantDebugging) { - print("changing orientation" - + " [old]MyAvatar.orientation="+MyAvatar.orientation.x + "," + MyAvatar.orientation.y + "," - + MyAvatar.orientation.z + "," + MyAvatar.orientation.w - + " newOrientation="+newOrientation.x + "," + newOrientation.y + "," + newOrientation.z + "," + newOrientation.w); - } - MyAvatar.orientation = newOrientation; - yawFromMouse = 0; - - // apply pitch from mouse - var newPitch = MyAvatar.headPitch + pitchFromMouse; - if (wantDebugging) { - print("changing pitch [old]MyAvatar.headPitch="+MyAvatar.headPitch+ " newPitch="+newPitch); - } - MyAvatar.headPitch = newPitch; - pitchFromMouse = 0; - } -} - -// Map the mouse events to our functions -Controller.touchBeginEvent.connect(touchBeginEvent); -Controller.touchUpdateEvent.connect(touchUpdateEvent); -Controller.touchEndEvent.connect(touchEndEvent); - -// disable the standard application for mouse events -Controller.captureTouchEvents(); - -function scriptEnding() { - // re-enabled the standard application for mouse events - Controller.releaseTouchEvents(); -} - -// would be nice to change to update -Script.update.connect(update); -Script.scriptEnding.connect(scriptEnding); From e87e0a1e0b35fefe09807acc525f5e1097333b6f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 11 Mar 2015 12:10:37 -0700 Subject: [PATCH 24/26] some cleanup of dead code related to timers --- assignment-client/src/Agent.cpp | 1 - assignment-client/src/audio/AudioMixer.cpp | 1 - interface/src/ui/BandwidthDialog.h | 1 + libraries/networking/src/BandwidthRecorder.h | 1 - libraries/networking/src/DomainHandler.cpp | 7 ------- libraries/networking/src/DomainHandler.h | 1 - 6 files changed, 1 insertion(+), 11 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d56db7aace..ed1f293c06 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index e865ab0035..dd566bc40b 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #include diff --git a/interface/src/ui/BandwidthDialog.h b/interface/src/ui/BandwidthDialog.h index a504a5964f..1fc8627191 100644 --- a/interface/src/ui/BandwidthDialog.h +++ b/interface/src/ui/BandwidthDialog.h @@ -16,6 +16,7 @@ #include #include #include +#include #include "Node.h" #include "BandwidthRecorder.h" diff --git a/libraries/networking/src/BandwidthRecorder.h b/libraries/networking/src/BandwidthRecorder.h index a7f51fbb45..c22665d2cc 100644 --- a/libraries/networking/src/BandwidthRecorder.h +++ b/libraries/networking/src/BandwidthRecorder.h @@ -16,7 +16,6 @@ #include #include -#include #include "DependencyManager.h" #include "Node.h" #include "SimpleMovingAverage.h" diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index fe50647c20..78ec64832b 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -32,7 +32,6 @@ DomainHandler::DomainHandler(QObject* parent) : _iceServerSockAddr(), _icePeer(), _isConnected(false), - _handshakeTimer(NULL), _settingsObject(), _failedSettingsRequests(0) { @@ -50,12 +49,6 @@ void DomainHandler::clearConnectionInfo() { } setIsConnected(false); - - if (_handshakeTimer) { - _handshakeTimer->stop(); - delete _handshakeTimer; - _handshakeTimer = NULL; - } } void DomainHandler::clearSettings() { diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 295e6eac01..0877f657e1 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -100,7 +100,6 @@ private: HifiSockAddr _iceServerSockAddr; NetworkPeer _icePeer; bool _isConnected; - QTimer* _handshakeTimer; QJsonObject _settingsObject; int _failedSettingsRequests; }; From cab6cc8c75ab62f94cb0a99c5b4a3cfeceb4975c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 11 Mar 2015 16:30:21 -0700 Subject: [PATCH 25/26] fix crash on exit related to AvatarManager using TextureCach resources --- interface/src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a7a6c8c094..1e21144546 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -612,7 +612,8 @@ Application::~Application() { // stop the glWidget frame timer so it doesn't call paintGL _glWidget->stopFrameTimer(); - + + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); From d3bc54091937240832cb31d3ed7e6a1c84f9f3d9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 11 Mar 2015 16:42:29 -0700 Subject: [PATCH 26/26] use glm from hifi S3 now that fedora is down --- cmake/externals/glm/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/externals/glm/CMakeLists.txt b/cmake/externals/glm/CMakeLists.txt index 6e5b1ef870..7825e2c117 100644 --- a/cmake/externals/glm/CMakeLists.txt +++ b/cmake/externals/glm/CMakeLists.txt @@ -3,7 +3,7 @@ set(EXTERNAL_NAME glm) include(ExternalProject) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://pkgs.fedoraproject.org/repo/pkgs/glm/glm-0.9.5.4.zip/fab76fc982b256b46208e5c750ed456a/glm-0.9.5.4.zip + URL http://hifi-public.s3.amazonaws.com/dependencies/glm-0.9.5.4.zip URL_MD5 fab76fc982b256b46208e5c750ed456a BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=