mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 14:01:38 +02:00
Merge branch 'master' of https://github.com/worklist/hifi
This commit is contained in:
commit
dd352e5a1a
14 changed files with 169 additions and 220 deletions
|
@ -17,10 +17,6 @@
|
|||
Script.include("../../libraries/entityPropertyDialogBox.js");
|
||||
var entityPropertyDialogBox = EntityPropertyDialogBox;
|
||||
|
||||
var LASER_WIDTH = 4;
|
||||
var LASER_COLOR = { red: 255, green: 0, blue: 0 };
|
||||
var LASER_LENGTH_FACTOR = 500;
|
||||
|
||||
var MIN_ANGULAR_SIZE = 2;
|
||||
var MAX_ANGULAR_SIZE = 45;
|
||||
var allowLargeModels = true;
|
||||
|
@ -32,7 +28,44 @@ var RIGHT = 1;
|
|||
|
||||
var jointList = MyAvatar.getJointNames();
|
||||
|
||||
var mode = 0;
|
||||
var STICKS = 0;
|
||||
var MAPPED = 1;
|
||||
var mode = STICKS;
|
||||
|
||||
var LASER_WIDTH = 4;
|
||||
var LASER_COLOR = [{ red: 200, green: 150, blue: 50 }, // STICKS
|
||||
{ red: 50, green: 150, blue: 200 }]; // MAPPED
|
||||
var LASER_LENGTH_FACTOR = 500;
|
||||
|
||||
var lastAccurateIntersection = null;
|
||||
var accurateIntersections = 0;
|
||||
var totalIntersections = 0;
|
||||
var inaccurateInARow = 0;
|
||||
var maxInaccurateInARow = 0;
|
||||
function getRayIntersection(pickRay) { // pickRay : { origin : {xyz}, direction : {xyz} }
|
||||
if (lastAccurateIntersection === null) {
|
||||
lastAccurateIntersection = Entities.findRayIntersectionBlocking(pickRay);
|
||||
} else {
|
||||
var intersection = Entities.findRayIntersection(pickRay);
|
||||
if (intersection.accurate) {
|
||||
lastAccurateIntersection = intersection;
|
||||
accurateIntersections++;
|
||||
maxInaccurateInARow = (maxInaccurateInARow > inaccurateInARow) ? maxInaccurateInARow : inaccurateInARow;
|
||||
inaccurateInARow = 0;
|
||||
} else {
|
||||
inaccurateInARow++;
|
||||
}
|
||||
totalIntersections++;
|
||||
}
|
||||
return lastAccurateIntersection;
|
||||
}
|
||||
|
||||
function printIntersectionsStats() {
|
||||
var ratio = accurateIntersections / totalIntersections;
|
||||
print("Out of " + totalIntersections + " intersections, " + accurateIntersections + " where accurate. (" + ratio * 100 +"%)");
|
||||
print("Worst case was " + maxInaccurateInARow + " inaccurate intersections in a row.");
|
||||
}
|
||||
|
||||
|
||||
function controller(wichSide) {
|
||||
this.side = wichSide;
|
||||
|
@ -42,10 +75,10 @@ function controller(wichSide) {
|
|||
this.bumper = 6 * wichSide + 5;
|
||||
|
||||
this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
this.palmPosition = Controller.getSpatialControlPosition(this.palm);
|
||||
this.palmPosition = this.oldPalmPosition;
|
||||
|
||||
this.oldTipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
this.tipPosition = Controller.getSpatialControlPosition(this.tip);
|
||||
this.tipPosition = this.oldTipPosition;
|
||||
|
||||
this.oldUp = Controller.getSpatialControlNormal(this.palm);
|
||||
this.up = this.oldUp;
|
||||
|
@ -82,7 +115,7 @@ function controller(wichSide) {
|
|||
this.laser = Overlays.addOverlay("line3d", {
|
||||
start: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
color: LASER_COLOR,
|
||||
color: LASER_COLOR[mode],
|
||||
alpha: 1,
|
||||
visible: false,
|
||||
lineWidth: LASER_WIDTH,
|
||||
|
@ -254,9 +287,9 @@ function controller(wichSide) {
|
|||
|
||||
var inverseRotation = Quat.inverse(MyAvatar.orientation);
|
||||
var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position));
|
||||
startPosition = Vec3.multiply(startPosition, 1 / MyAvatar.scale);
|
||||
var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition));
|
||||
var distance = Vec3.length(direction);
|
||||
direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / distance);
|
||||
direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / (Vec3.length(direction) * MyAvatar.scale));
|
||||
var endPosition = Vec3.sum(startPosition, direction);
|
||||
|
||||
Overlays.editOverlay(this.laser, {
|
||||
|
@ -276,17 +309,16 @@ function controller(wichSide) {
|
|||
start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)),
|
||||
end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale))
|
||||
});
|
||||
this.showLaser(!this.grabbing || mode == 0);
|
||||
this.showLaser(!this.grabbing || mode == STICKS);
|
||||
|
||||
if (this.glowedIntersectingModel.isKnownID) {
|
||||
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 });
|
||||
this.glowedIntersectingModel.isKnownID = false;
|
||||
}
|
||||
if (!this.grabbing) {
|
||||
var intersection = Entities.findRayIntersectionBlocking({
|
||||
origin: this.palmPosition,
|
||||
direction: this.front
|
||||
});
|
||||
var intersection = getRayIntersection({ origin: this.palmPosition,
|
||||
direction: this.front
|
||||
});
|
||||
|
||||
var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0;
|
||||
|
||||
|
@ -313,17 +345,16 @@ function controller(wichSide) {
|
|||
if (this.grabbing) {
|
||||
if (!this.entityID.isKnownID) {
|
||||
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
|
||||
this.entityID = Entities.findRayIntersectionBlocking({
|
||||
origin: this.palmPosition,
|
||||
direction: this.front
|
||||
}).entityID;
|
||||
this.entityID = getRayIntersection({ origin: this.palmPosition,
|
||||
direction: this.front
|
||||
}).entityID;
|
||||
print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
|
||||
}
|
||||
var newPosition;
|
||||
var newRotation;
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
case STICKS:
|
||||
newPosition = Vec3.sum(this.palmPosition,
|
||||
Vec3.multiply(this.front, this.x));
|
||||
newPosition = Vec3.sum(newPosition,
|
||||
|
@ -337,7 +368,7 @@ function controller(wichSide) {
|
|||
newRotation = Quat.multiply(newRotation,
|
||||
this.oldModelRotation);
|
||||
break;
|
||||
case 1:
|
||||
case MAPPED:
|
||||
var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 });
|
||||
var d = Vec3.dot(forward, MyAvatar.position);
|
||||
|
||||
|
@ -406,15 +437,13 @@ function controller(wichSide) {
|
|||
|
||||
var bumperValue = Controller.isButtonPressed(this.bumper);
|
||||
if (bumperValue && !this.bumperValue) {
|
||||
if (mode == 0) {
|
||||
mode = 1;
|
||||
Overlays.editOverlay(leftController.laser, { color: { red: 0, green: 0, blue: 255 } });
|
||||
Overlays.editOverlay(rightController.laser, { color: { red: 0, green: 0, blue: 255 } });
|
||||
} else {
|
||||
mode = 0;
|
||||
Overlays.editOverlay(leftController.laser, { color: { red: 255, green: 0, blue: 0 } });
|
||||
Overlays.editOverlay(rightController.laser, { color: { red: 255, green: 0, blue: 0 } });
|
||||
if (mode === STICKS) {
|
||||
mode = MAPPED;
|
||||
} else if (mode === MAPPED) {
|
||||
mode = STICKS;
|
||||
}
|
||||
Overlays.editOverlay(leftController.laser, { color: LASER_COLOR[mode] });
|
||||
Overlays.editOverlay(rightController.laser, { color: LASER_COLOR[mode] });
|
||||
}
|
||||
this.bumperValue = bumperValue;
|
||||
|
||||
|
@ -484,10 +513,10 @@ function controller(wichSide) {
|
|||
Vec3.print("Looking at: ", this.palmPosition);
|
||||
var pickRay = { origin: this.palmPosition,
|
||||
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) };
|
||||
var foundIntersection = Entities.findRayIntersectionBlocking(pickRay);
|
||||
var foundIntersection = getRayIntersection(pickRay);
|
||||
|
||||
if(!foundIntersection.accurate) {
|
||||
print("No accurate intersection");
|
||||
if(!foundIntersection.intersects) {
|
||||
print("No intersection");
|
||||
return;
|
||||
}
|
||||
newModel = foundIntersection.entityID;
|
||||
|
@ -535,7 +564,7 @@ function moveEntities() {
|
|||
|
||||
|
||||
switch (mode) {
|
||||
case 0:
|
||||
case STICKS:
|
||||
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
|
||||
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
|
||||
|
||||
|
@ -554,7 +583,7 @@ function moveEntities() {
|
|||
newPosition = Vec3.sum(middle,
|
||||
Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio));
|
||||
break;
|
||||
case 1:
|
||||
case MAPPED:
|
||||
var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition));
|
||||
var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition));
|
||||
|
||||
|
@ -637,43 +666,56 @@ var glowedEntityID = { id: -1, isKnownID: false };
|
|||
// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already
|
||||
// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that
|
||||
// added it.
|
||||
var ROOT_MENU = "Edit";
|
||||
var ITEM_BEFORE = "Physics";
|
||||
var MENU_SEPARATOR = "Models";
|
||||
var EDIT_PROPERTIES = "Edit Properties...";
|
||||
var INTERSECTION_STATS = "Print Intersection Stats";
|
||||
var DELETE = "Delete";
|
||||
var LARGE_MODELS = "Allow Selecting of Large Models";
|
||||
var SMALL_MODELS = "Allow Selecting of Small Models";
|
||||
var LIGHTS = "Allow Selecting of Lights";
|
||||
|
||||
var modelMenuAddedDelete = false;
|
||||
var originalLightsArePickable = Entities.getLightsArePickable();
|
||||
function setupModelMenus() {
|
||||
print("setupModelMenus()");
|
||||
// adj our menuitems
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...",
|
||||
shortcutKeyEvent: { text: "`" }, afterItem: "Models" });
|
||||
if (!Menu.menuItemExists("Edit", "Delete")) {
|
||||
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: MENU_SEPARATOR, isSeparator: true, beforeItem: ITEM_BEFORE });
|
||||
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: EDIT_PROPERTIES,
|
||||
shortcutKeyEvent: { text: "`" }, afterItem: MENU_SEPARATOR });
|
||||
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: INTERSECTION_STATS, afterItem: MENU_SEPARATOR });
|
||||
if (!Menu.menuItemExists(ROOT_MENU, DELETE)) {
|
||||
print("no delete... adding ours");
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete",
|
||||
shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" });
|
||||
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: DELETE,
|
||||
shortcutKeyEvent: { text: "backspace" }, afterItem: MENU_SEPARATOR });
|
||||
modelMenuAddedDelete = true;
|
||||
} else {
|
||||
print("delete exists... don't add ours");
|
||||
}
|
||||
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L",
|
||||
afterItem: "Paste Models", isCheckable: true });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S",
|
||||
afterItem: "Allow Selecting of Large Models", isCheckable: true });
|
||||
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L",
|
||||
afterItem: "Allow Selecting of Small Models", isCheckable: true });
|
||||
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: LARGE_MODELS, shortcutKey: "CTRL+META+L",
|
||||
afterItem: DELETE, isCheckable: true });
|
||||
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: SMALL_MODELS, shortcutKey: "CTRL+META+S",
|
||||
afterItem: LARGE_MODELS, isCheckable: true });
|
||||
Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: LIGHTS, shortcutKey: "CTRL+SHIFT+META+L",
|
||||
afterItem: SMALL_MODELS, isCheckable: true });
|
||||
|
||||
Entities.setLightsArePickable(false);
|
||||
}
|
||||
|
||||
function cleanupModelMenus() {
|
||||
Menu.removeMenuItem("Edit", "Edit Properties...");
|
||||
Menu.removeSeparator(ROOT_MENU, MENU_SEPARATOR);
|
||||
Menu.removeMenuItem(ROOT_MENU, EDIT_PROPERTIES);
|
||||
Menu.removeMenuItem(ROOT_MENU, INTERSECTION_STATS);
|
||||
if (modelMenuAddedDelete) {
|
||||
// delete our menuitems
|
||||
Menu.removeMenuItem("Edit", "Delete");
|
||||
Menu.removeMenuItem(ROOT_MENU, DELETE);
|
||||
}
|
||||
|
||||
Menu.removeMenuItem("Edit", "Allow Selecting of Large Models");
|
||||
Menu.removeMenuItem("Edit", "Allow Selecting of Small Models");
|
||||
Menu.removeMenuItem("Edit", "Allow Selecting of Lights");
|
||||
Menu.removeMenuItem(ROOT_MENU, LARGE_MODELS);
|
||||
Menu.removeMenuItem(ROOT_MENU, SMALL_MODELS);
|
||||
Menu.removeMenuItem(ROOT_MENU, LIGHTS);
|
||||
|
||||
}
|
||||
|
||||
|
@ -697,13 +739,13 @@ function showPropertiesForm(editModelID) {
|
|||
|
||||
Menu.menuItemEvent.connect(function (menuItem) {
|
||||
print("menuItemEvent() in JS... menuItem=" + menuItem);
|
||||
if (menuItem == "Allow Selecting of Small Models") {
|
||||
allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models");
|
||||
} else if (menuItem == "Allow Selecting of Large Models") {
|
||||
allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models");
|
||||
} else if (menuItem == "Allow Selecting of Lights") {
|
||||
Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights"));
|
||||
} else if (menuItem == "Delete") {
|
||||
if (menuItem == SMALL_MODELS) {
|
||||
allowSmallModels = Menu.isOptionChecked(SMALL_MODELS);
|
||||
} else if (menuItem == LARGE_MODELS) {
|
||||
allowLargeModels = Menu.isOptionChecked(LARGE_MODELS);
|
||||
} else if (menuItem == LIGHTS) {
|
||||
Entities.setLightsArePickable(Menu.isOptionChecked(LIGHTS));
|
||||
} else if (menuItem == DELETE) {
|
||||
if (leftController.grabbing) {
|
||||
print(" Delete Entity.... leftController.entityID="+ leftController.entityID);
|
||||
Entities.deleteEntity(leftController.entityID);
|
||||
|
@ -721,7 +763,7 @@ Menu.menuItemEvent.connect(function (menuItem) {
|
|||
} else {
|
||||
print(" Delete Entity.... not holding...");
|
||||
}
|
||||
} else if (menuItem == "Edit Properties...") {
|
||||
} else if (menuItem == EDIT_PROPERTIES) {
|
||||
editModelID = -1;
|
||||
if (leftController.grabbing) {
|
||||
print(" Edit Properties.... leftController.entityID="+ leftController.entityID);
|
||||
|
@ -736,16 +778,18 @@ Menu.menuItemEvent.connect(function (menuItem) {
|
|||
print(" Edit Properties.... about to edit properties...");
|
||||
showPropertiesForm(editModelID);
|
||||
}
|
||||
} else if (menuItem == INTERSECTION_STATS) {
|
||||
printIntersectionsStats();
|
||||
}
|
||||
});
|
||||
|
||||
Controller.keyReleaseEvent.connect(function (event) {
|
||||
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
|
||||
if (event.text == "`") {
|
||||
handeMenuEvent("Edit Properties...");
|
||||
handeMenuEvent(EDIT_PROPERTIES);
|
||||
}
|
||||
if (event.text == "BACKSPACE") {
|
||||
handeMenuEvent("Delete");
|
||||
handeMenuEvent(DELETE);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -173,23 +173,12 @@ void IceServer::clearInactivePeers() {
|
|||
bool IceServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||
//
|
||||
// We need an HTTP handler in order to monitor the health of the ice server
|
||||
// The correct functioning of the ICE server will first be determined by its HTTP availability,
|
||||
// and then by the existence of a minimum number of peers in the list, matching the minimum number of
|
||||
// domains in production by High Fidelity.
|
||||
// The correct functioning of the ICE server will be determined by its HTTP availability,
|
||||
//
|
||||
|
||||
int MINIMUM_PEERS = 3;
|
||||
bool IS_HEALTHY = false;
|
||||
|
||||
IS_HEALTHY = _activePeers.size() >= MINIMUM_PEERS ? true : false;
|
||||
|
||||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
|
||||
if (url.path() == "/status") {
|
||||
if (IS_HEALTHY) {
|
||||
connection->respond(HTTPConnection::StatusCode200, QByteArray::number(_activePeers.size()));
|
||||
} else {
|
||||
connection->respond(HTTPConnection::StatusCode404, QByteArray::number(_activePeers.size()));
|
||||
}
|
||||
connection->respond(HTTPConnection::StatusCode200, QByteArray::number(_activePeers.size()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -118,7 +118,9 @@ void Audio::audioMixerKilled() {
|
|||
|
||||
QAudioDeviceInfo getNamedAudioDeviceForMode(QAudio::Mode mode, const QString& deviceName) {
|
||||
QAudioDeviceInfo result;
|
||||
#ifdef WIN32
|
||||
// Temporarily enable audio device selection in Windows again to test how it behaves now
|
||||
//#ifdef WIN32
|
||||
#if FALSE
|
||||
// NOTE
|
||||
// this is a workaround for a windows only QtBug https://bugreports.qt-project.org/browse/QTBUG-16117
|
||||
// static QAudioDeviceInfo objects get deallocated when QList<QAudioDevieInfo> objects go out of scope
|
||||
|
|
|
@ -171,10 +171,6 @@ void Hand::renderHandTargets(bool isMine) {
|
|||
glm::vec3 tip = palm.getTipPosition();
|
||||
glm::vec3 root = palm.getPosition();
|
||||
|
||||
//Scale the positions based on avatar scale
|
||||
myAvatar->scaleVectorRelativeToPosition(tip);
|
||||
myAvatar->scaleVectorRelativeToPosition(root);
|
||||
|
||||
Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS);
|
||||
// Render sphere at palm/finger root
|
||||
glm::vec3 offsetFromPalm = root + palm.getNormal() * PALM_DISK_THICKNESS;
|
||||
|
|
|
@ -27,7 +27,7 @@ HandData::HandData(AvatarData* owningAvatar) :
|
|||
}
|
||||
|
||||
glm::vec3 HandData::worldToLocalVector(const glm::vec3& worldVector) const {
|
||||
return glm::inverse(getBaseOrientation()) * worldVector;
|
||||
return glm::inverse(getBaseOrientation()) * worldVector / getBaseScale();
|
||||
}
|
||||
|
||||
PalmData& HandData::addNewPalm() {
|
||||
|
@ -108,15 +108,19 @@ glm::quat HandData::getBaseOrientation() const {
|
|||
glm::vec3 HandData::getBasePosition() const {
|
||||
return _owningAvatarData->getPosition();
|
||||
}
|
||||
|
||||
float HandData::getBaseScale() const {
|
||||
return _owningAvatarData->getTargetScale();
|
||||
}
|
||||
|
||||
glm::vec3 PalmData::getFingerDirection() const {
|
||||
const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 0.0f, 1.0f);
|
||||
return _owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION);
|
||||
return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION));
|
||||
}
|
||||
|
||||
glm::vec3 PalmData::getNormal() const {
|
||||
const glm::vec3 LOCAL_PALM_DIRECTION(0.0f, -1.0f, 0.0f);
|
||||
return _owningHandData->localToWorldDirection(_rawRotation * LOCAL_PALM_DIRECTION);
|
||||
return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_PALM_DIRECTION));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,11 +36,11 @@ public:
|
|||
|
||||
// position conversion
|
||||
glm::vec3 localToWorldPosition(const glm::vec3& localPosition) {
|
||||
return getBasePosition() + getBaseOrientation() * localPosition;
|
||||
return getBasePosition() + getBaseOrientation() * localPosition * getBaseScale();
|
||||
}
|
||||
|
||||
glm::vec3 localToWorldDirection(const glm::vec3& localVector) {
|
||||
return getBaseOrientation() * localVector;
|
||||
return getBaseOrientation() * localVector * getBaseScale();
|
||||
}
|
||||
|
||||
glm::vec3 worldToLocalVector(const glm::vec3& worldVector) const;
|
||||
|
@ -71,6 +71,7 @@ protected:
|
|||
|
||||
glm::quat getBaseOrientation() const;
|
||||
glm::vec3 getBasePosition() const;
|
||||
float getBaseScale() const;
|
||||
|
||||
private:
|
||||
// privatize copy ctor and assignment operator so copies of this object cannot be made
|
||||
|
|
|
@ -140,9 +140,17 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
|||
ByteCountCoded<quint32> typeCoder = getType();
|
||||
QByteArray encodedType = typeCoder;
|
||||
|
||||
quint64 updateDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited();
|
||||
// last updated (animations, non-physics changes)
|
||||
quint64 updateDelta = getLastUpdated() <= getLastEdited() ? 0 : getLastUpdated() - getLastEdited();
|
||||
ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
|
||||
QByteArray encodedUpdateDelta = updateDeltaCoder;
|
||||
|
||||
// last simulated (velocity, angular velocity, physics changes)
|
||||
quint64 simulatedDelta = getLastSimulated() <= getLastEdited() ? 0 : getLastSimulated() - getLastEdited();
|
||||
ByteCountCoded<quint64> simulatedDeltaCoder = simulatedDelta;
|
||||
QByteArray encodedSimulatedDelta = simulatedDeltaCoder;
|
||||
|
||||
|
||||
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
|
||||
EntityPropertyFlags requestedProperties = getEntityProperties(params);
|
||||
EntityPropertyFlags propertiesDidntFit = requestedProperties;
|
||||
|
@ -170,6 +178,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
|||
bool successCreatedFits = false;
|
||||
bool successLastEditedFits = false;
|
||||
bool successLastUpdatedFits = false;
|
||||
bool successLastSimulatedFits = false;
|
||||
bool successPropertyFlagsFits = false;
|
||||
int propertyFlagsOffset = 0;
|
||||
int oldPropertyFlagsLength = 0;
|
||||
|
@ -189,8 +198,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
|
|||
if (successLastEditedFits) {
|
||||
successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
|
||||
}
|
||||
|
||||
if (successLastUpdatedFits) {
|
||||
successLastSimulatedFits = packetData->appendValue(encodedSimulatedDelta);
|
||||
}
|
||||
|
||||
if (successLastSimulatedFits) {
|
||||
propertyFlagsOffset = packetData->getUncompressedByteOffset();
|
||||
encodedPropertyFlags = propertyFlags;
|
||||
oldPropertyFlagsLength = encodedPropertyFlags.length();
|
||||
|
@ -458,6 +470,25 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
encodedUpdateDelta = updateDeltaCoder; // determine true length
|
||||
dataAt += encodedUpdateDelta.size();
|
||||
bytesRead += encodedUpdateDelta.size();
|
||||
|
||||
// Newer bitstreams will have a last simulated and a last updated value
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) {
|
||||
// last simulated is stored as ByteCountCoded delta from lastEdited
|
||||
QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||
ByteCountCoded<quint64> simulatedDeltaCoder = encodedSimulatedDelta;
|
||||
quint64 simulatedDelta = simulatedDeltaCoder;
|
||||
if (overwriteLocalData) {
|
||||
_lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that
|
||||
if (wantDebug) {
|
||||
qDebug() << "_lastSimulated =" << _lastSimulated;
|
||||
qDebug() << "_lastEdited=" << _lastEdited;
|
||||
qDebug() << "lastEditedFromBufferAdjusted=" << lastEditedFromBufferAdjusted;
|
||||
}
|
||||
}
|
||||
encodedSimulatedDelta = simulatedDeltaCoder; // determine true length
|
||||
dataAt += encodedSimulatedDelta.size();
|
||||
bytesRead += encodedSimulatedDelta.size();
|
||||
}
|
||||
|
||||
// Property Flags
|
||||
QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
|
||||
|
@ -521,6 +552,12 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
|
||||
recalculateCollisionShape();
|
||||
if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) {
|
||||
// TODO: Andrew & Brad to discuss -- this probably should not be "now" but instead should be the last
|
||||
// simulated time from server. The logic should maybe be: the position changed from the server, so the
|
||||
// position we just set can be thought of as the position at the time it was last simulated by the
|
||||
// server (clock skew adjusted). By setting it to "now" we are saying that the last position is to be
|
||||
// considered to be the correct position for "now" which is likely in the future from when it actually
|
||||
// was at that last known positition.
|
||||
_lastSimulated = now;
|
||||
}
|
||||
}
|
||||
|
@ -833,6 +870,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
setLastEdited(now);
|
||||
}
|
||||
if (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) {
|
||||
// TODO: Andrew & Brad to discuss. Is this correct? Maybe it is. Need to think through all cases.
|
||||
_lastSimulated = now;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,6 +126,7 @@ public:
|
|||
|
||||
// perform update
|
||||
virtual void update(const quint64& now) { _lastUpdated = now; }
|
||||
quint64 getLastUpdated() const { return _lastUpdated; }
|
||||
|
||||
// perform linear extrapolation for SimpleEntitySimulation
|
||||
void simulate(const quint64& now);
|
||||
|
@ -296,9 +297,10 @@ protected:
|
|||
QUuid _id;
|
||||
uint32_t _creatorTokenID;
|
||||
bool _newlyCreated;
|
||||
quint64 _lastSimulated; // last time this entity called simulate()
|
||||
quint64 _lastUpdated; // last time this entity called update()
|
||||
quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, and physics changes
|
||||
quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes
|
||||
quint64 _lastEdited; // last official local or remote edit time
|
||||
|
||||
quint64 _lastEditedFromRemote; // last time we received and edit from the server
|
||||
quint64 _lastEditedFromRemoteInRemoteTime; // last time we received and edit from the server (in server-time-frame)
|
||||
quint64 _created;
|
||||
|
|
|
@ -60,7 +60,8 @@ public:
|
|||
// own definition. Implement these to allow your octree based server to support editing
|
||||
virtual bool getWantSVOfileVersions() const { return true; }
|
||||
virtual PacketType expectedDataPacketType() const { return PacketTypeEntityData; }
|
||||
virtual bool canProcessVersion(PacketVersion thisVersion) const { return true; } // we support all versions
|
||||
virtual bool canProcessVersion(PacketVersion thisVersion) const
|
||||
{ return thisVersion >= VERSION_ENTITIES_SUPPORT_SPLIT_MTU; } // we support all versions with split mtu
|
||||
virtual bool handlesEditPacketType(PacketType packetType) const;
|
||||
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode);
|
||||
|
|
|
@ -81,17 +81,6 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
return somethingChanged;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ModelEntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {
|
||||
return oldVersionReadEntityDataFromBuffer(data, bytesLeftToRead, args);
|
||||
}
|
||||
|
||||
// let our base class do most of the work... it will call us back for our porition...
|
||||
return EntityItem::readEntityDataFromBuffer(data, bytesLeftToRead, args);
|
||||
}
|
||||
|
||||
int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
||||
|
@ -131,122 +120,6 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
return bytesRead;
|
||||
}
|
||||
|
||||
int ModelEntityItem::oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args) {
|
||||
|
||||
int bytesRead = 0;
|
||||
if (bytesLeftToRead >= expectedBytes()) {
|
||||
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
|
||||
|
||||
const unsigned char* dataAt = data;
|
||||
|
||||
// id
|
||||
// this old bitstream format had 32bit IDs. They are obsolete and need to be replaced with our new UUID
|
||||
// format. We can simply read and ignore the old ID since they should not be repeated. This code should only
|
||||
// run on loading from an old file.
|
||||
quint32 oldID;
|
||||
memcpy(&oldID, dataAt, sizeof(oldID));
|
||||
dataAt += sizeof(oldID);
|
||||
bytesRead += sizeof(oldID);
|
||||
_id = QUuid::createUuid();
|
||||
|
||||
// _lastUpdated
|
||||
memcpy(&_lastUpdated, dataAt, sizeof(_lastUpdated));
|
||||
dataAt += sizeof(_lastUpdated);
|
||||
bytesRead += sizeof(_lastUpdated);
|
||||
_lastUpdated -= clockSkew;
|
||||
|
||||
// _lastEdited
|
||||
memcpy(&_lastEdited, dataAt, sizeof(_lastEdited));
|
||||
dataAt += sizeof(_lastEdited);
|
||||
bytesRead += sizeof(_lastEdited);
|
||||
_lastEdited -= clockSkew;
|
||||
_created = _lastEdited; // NOTE: old models didn't have age or created time, assume their last edit was a create
|
||||
|
||||
QString ageAsString = formatSecondsElapsed(getAge());
|
||||
qDebug() << "Loading old model file, _created = _lastEdited =" << _created
|
||||
<< " age=" << getAge() << "seconds - " << ageAsString
|
||||
<< "old ID=" << oldID << "new ID=" << _id;
|
||||
|
||||
// radius
|
||||
float radius;
|
||||
memcpy(&radius, dataAt, sizeof(radius));
|
||||
dataAt += sizeof(radius);
|
||||
bytesRead += sizeof(radius);
|
||||
setRadius(radius);
|
||||
|
||||
// position
|
||||
memcpy(&_position, dataAt, sizeof(_position));
|
||||
dataAt += sizeof(_position);
|
||||
bytesRead += sizeof(_position);
|
||||
|
||||
// color
|
||||
memcpy(&_color, dataAt, sizeof(_color));
|
||||
dataAt += sizeof(_color);
|
||||
bytesRead += sizeof(_color);
|
||||
|
||||
// TODO: how to handle this? Presumable, this would only ever be true if the model file was saved with
|
||||
// a model being in a shouldBeDeleted state. Which seems unlikely. But if it happens, maybe we should delete the entity after loading?
|
||||
// shouldBeDeleted
|
||||
bool shouldBeDeleted = false;
|
||||
memcpy(&shouldBeDeleted, dataAt, sizeof(shouldBeDeleted));
|
||||
dataAt += sizeof(shouldBeDeleted);
|
||||
bytesRead += sizeof(shouldBeDeleted);
|
||||
if (shouldBeDeleted) {
|
||||
qDebug() << "UNEXPECTED - read shouldBeDeleted=TRUE from an old format file";
|
||||
}
|
||||
|
||||
// modelURL
|
||||
uint16_t modelURLLength;
|
||||
memcpy(&modelURLLength, dataAt, sizeof(modelURLLength));
|
||||
dataAt += sizeof(modelURLLength);
|
||||
bytesRead += sizeof(modelURLLength);
|
||||
QString modelURLString((const char*)dataAt);
|
||||
setModelURL(modelURLString);
|
||||
dataAt += modelURLLength;
|
||||
bytesRead += modelURLLength;
|
||||
|
||||
// rotation
|
||||
int bytes = unpackOrientationQuatFromBytes(dataAt, _rotation);
|
||||
dataAt += bytes;
|
||||
bytesRead += bytes;
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ANIMATION) {
|
||||
// animationURL
|
||||
uint16_t animationURLLength;
|
||||
memcpy(&animationURLLength, dataAt, sizeof(animationURLLength));
|
||||
dataAt += sizeof(animationURLLength);
|
||||
bytesRead += sizeof(animationURLLength);
|
||||
QString animationURLString((const char*)dataAt);
|
||||
setAnimationURL(animationURLString);
|
||||
dataAt += animationURLLength;
|
||||
bytesRead += animationURLLength;
|
||||
|
||||
// animationIsPlaying
|
||||
bool animationIsPlaying;
|
||||
memcpy(&animationIsPlaying, dataAt, sizeof(animationIsPlaying));
|
||||
dataAt += sizeof(animationIsPlaying);
|
||||
bytesRead += sizeof(animationIsPlaying);
|
||||
setAnimationIsPlaying(animationIsPlaying);
|
||||
|
||||
// animationFrameIndex
|
||||
float animationFrameIndex;
|
||||
memcpy(&animationFrameIndex, dataAt, sizeof(animationFrameIndex));
|
||||
dataAt += sizeof(animationFrameIndex);
|
||||
bytesRead += sizeof(animationFrameIndex);
|
||||
setAnimationFrameIndex(animationFrameIndex);
|
||||
|
||||
// animationFPS
|
||||
float animationFPS;
|
||||
memcpy(&animationFPS, dataAt, sizeof(animationFPS));
|
||||
dataAt += sizeof(animationFPS);
|
||||
bytesRead += sizeof(animationFPS);
|
||||
setAnimationFPS(animationFPS);
|
||||
}
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
|
||||
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||
EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||
|
|
|
@ -40,7 +40,6 @@ public:
|
|||
OctreeElement::AppendState& appendState) const;
|
||||
|
||||
|
||||
virtual int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||
|
@ -116,8 +115,6 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
/// For reading models from pre V3 bitstreams
|
||||
int oldVersionReadEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args);
|
||||
bool isAnimatingSomething() const;
|
||||
|
||||
rgbColor _color;
|
||||
|
|
|
@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
return 1;
|
||||
case PacketTypeEntityAddOrEdit:
|
||||
case PacketTypeEntityData:
|
||||
return VERSION_ENTITIES_HAVE_USER_DATA;
|
||||
return VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME;
|
||||
case PacketTypeEntityErase:
|
||||
return 2;
|
||||
case PacketTypeAudioStreamStats:
|
||||
|
|
|
@ -126,6 +126,7 @@ const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_
|
|||
const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4;
|
||||
const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6;
|
||||
const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7;
|
||||
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
|
@ -217,6 +217,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
|
|||
if (_numNonMovingUpdates <= 1) {
|
||||
// we only update lastEdited when we're sending new physics data
|
||||
// (i.e. NOT when we just simulate the positions forward, nore when we resend non-moving data)
|
||||
// NOTE: Andrew & Brad to discuss. Let's make sure we're using lastEdited, lastSimulated, and lastUpdated correctly
|
||||
quint64 lastSimulated = _entity->getLastSimulated();
|
||||
_entity->setLastEdited(lastSimulated);
|
||||
properties.setLastEdited(lastSimulated);
|
||||
|
|
Loading…
Reference in a new issue