Merge branch 'master' of git://github.com/highfidelity/hifi into entity-tool-properties

This commit is contained in:
Ryan Huffman 2014-11-14 10:53:18 -08:00
commit 28eebd3fa5
49 changed files with 601 additions and 89 deletions

View file

@ -17,12 +17,16 @@ var leapHands = (function () {
LEAP_ON_HMD_MENU_ITEM = "Leap Motion on HMD", LEAP_ON_HMD_MENU_ITEM = "Leap Motion on HMD",
LEAP_OFFSET = 0.019, // Thickness of Leap Motion plus HMD clip LEAP_OFFSET = 0.019, // Thickness of Leap Motion plus HMD clip
HMD_OFFSET = 0.070, // Eyeballs to front surface of Oculus DK2 TODO: Confirm and make depend on device and eye relief HMD_OFFSET = 0.070, // Eyeballs to front surface of Oculus DK2 TODO: Confirm and make depend on device and eye relief
hasHandAndWristJoints,
handToWristOffset = [], // For avatars without a wrist joint we control an estimate of a proper hand joint position
HAND_OFFSET = 0.4, // Relative distance of wrist to hand versus wrist to index finger knuckle
hands, hands,
wrists, wrists,
NUM_HANDS = 2, // 0 = left; 1 = right NUM_HANDS = 2, // 0 = left; 1 = right
fingers, fingers,
NUM_FINGERS = 5, // 0 = thumb; ...; 4 = pinky NUM_FINGERS = 5, // 0 = thumb; ...; 4 = pinky
THUMB = 0, THUMB = 0,
MIDDLE_FINGER = 2,
NUM_FINGER_JOINTS = 3, // 0 = metacarpal(hand)-proximal(finger) joint; ...; 2 = intermediate-distal joint NUM_FINGER_JOINTS = 3, // 0 = metacarpal(hand)-proximal(finger) joint; ...; 2 = intermediate-distal joint
MAX_HAND_INACTIVE_COUNT = 20, MAX_HAND_INACTIVE_COUNT = 20,
calibrationStatus, calibrationStatus,
@ -123,31 +127,42 @@ var leapHands = (function () {
function finishCalibration() { function finishCalibration() {
var avatarPosition, var avatarPosition,
avatarOrientation, handPosition,
avatarHandPosition, middleFingerPosition,
leapHandHeight, leapHandHeight,
h; h;
if (!isOnHMD) {
if (hands[0].controller.isActive() && hands[1].controller.isActive()) { if (hands[0].controller.isActive() && hands[1].controller.isActive()) {
leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0; leapHandHeight = (hands[0].controller.getAbsTranslation().y + hands[1].controller.getAbsTranslation().y) / 2.0;
} else { } else {
calibrationStatus = UNCALIBRATED; calibrationStatus = UNCALIBRATED;
return; return;
} }
}
avatarPosition = MyAvatar.position; avatarPosition = MyAvatar.position;
avatarOrientation = MyAvatar.orientation;
for (h = 0; h < NUM_HANDS; h += 1) { for (h = 0; h < NUM_HANDS; h += 1) {
avatarHandPosition = MyAvatar.getJointPosition(hands[h].jointName); handPosition = MyAvatar.getJointPosition(hands[h].jointName);
if (!hasHandAndWristJoints) {
middleFingerPosition = MyAvatar.getJointPosition(fingers[h][MIDDLE_FINGER][0].jointName);
handToWristOffset[h] = Vec3.multiply(Vec3.subtract(handPosition, middleFingerPosition), 1.0 - HAND_OFFSET);
}
if (isOnHMD) {
// Offset of Leap Motion origin from physical eye position
hands[h].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET };
} else {
hands[h].zeroPosition = { hands[h].zeroPosition = {
x: avatarHandPosition.x - avatarPosition.x, x: handPosition.x - avatarPosition.x,
y: avatarHandPosition.y - avatarPosition.y, y: handPosition.y - avatarPosition.y,
z: avatarPosition.z - avatarHandPosition.z z: avatarPosition.z - handPosition.z
}; };
hands[h].zeroPosition = Vec3.multiplyQbyV(MyAvatar.orientation, hands[h].zeroPosition); hands[h].zeroPosition = Vec3.multiplyQbyV(MyAvatar.orientation, hands[h].zeroPosition);
hands[h].zeroPosition.y = hands[h].zeroPosition.y - leapHandHeight; hands[h].zeroPosition.y = hands[h].zeroPosition.y - leapHandHeight;
} }
}
MyAvatar.clearJointData("LeftHand"); MyAvatar.clearJointData("LeftHand");
MyAvatar.clearJointData("LeftForeArm"); MyAvatar.clearJointData("LeftForeArm");
@ -161,6 +176,8 @@ var leapHands = (function () {
} }
function calibrate() { function calibrate() {
var jointNames,
i;
calibrationStatus = CALIBRATING; calibrationStatus = CALIBRATING;
@ -168,6 +185,13 @@ var leapHands = (function () {
avatarFaceModelURL = MyAvatar.faceModelURL; avatarFaceModelURL = MyAvatar.faceModelURL;
avatarSkeletonModelURL = MyAvatar.skeletonModelURL; avatarSkeletonModelURL = MyAvatar.skeletonModelURL;
// Does this skeleton have both wrist and hand joints?
hasHandAndWristJoints = false;
jointNames = MyAvatar.getJointNames();
for (i = 0; i < jointNames.length; i += 1) {
hasHandAndWristJoints = hasHandAndWristJoints || jointNames[i].toLowerCase() === "leftwrist";
}
// Set avatar arms vertical, forearms horizontal, as "zero" position for calibration // Set avatar arms vertical, forearms horizontal, as "zero" position for calibration
MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, -90.0)); MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, -90.0));
MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0)); MyAvatar.setJointData("LeftForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0));
@ -176,6 +200,7 @@ var leapHands = (function () {
MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0)); MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 180.0));
MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0));
// Wait for arms to assume their positions before calculating // Wait for arms to assume their positions before calculating
Script.setTimeout(finishCalibration, CALIBRATION_TIME); Script.setTimeout(finishCalibration, CALIBRATION_TIME);
} }
@ -195,37 +220,34 @@ var leapHands = (function () {
function setIsOnHMD() { function setIsOnHMD() {
isOnHMD = Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM); isOnHMD = Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM);
if (isOnHMD) { print("Leap Motion: " + (isOnHMD ? "Is on HMD" : "Is on desk"));
print("Leap Motion: Is on HMD");
// Offset of Leap Motion origin from physical eye position
hands[0].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET };
hands[1].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET };
calibrationStatus = CALIBRATED;
} else {
print("Leap Motion: Is on desk");
calibrationStatus = UNCALIBRATED;
}
} }
function checkSettings() { function checkSettings() {
// There is no "scale changed" event so we need check periodically. if (calibrationStatus > UNCALIBRATED && (MyAvatar.scale !== avatarScale
if (!isOnHMD && calibrationStatus > UNCALIBRATED && (MyAvatar.scale !== avatarScale
|| MyAvatar.faceModelURL !== avatarFaceModelURL || MyAvatar.faceModelURL !== avatarFaceModelURL
|| MyAvatar.skeletonModelURL !== avatarSkeletonModelURL)) { || MyAvatar.skeletonModelURL !== avatarSkeletonModelURL
print("Leap Motion: Recalibrate because avatar body or scale changed"); || Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM) !== isOnHMD)) {
print("Leap Motion: Recalibrate...");
calibrationStatus = UNCALIBRATED; calibrationStatus = UNCALIBRATED;
}
// There is a "menu changed" event but we may as well check here.
if (isOnHMD !== Menu.isOptionChecked(LEAP_ON_HMD_MENU_ITEM)) {
setIsOnHMD(); setIsOnHMD();
} }
} }
function setUp() { function setUp() {
wrists = [
{
jointName: "LeftWrist",
controller: Controller.createInputController("Spatial", "joint_L_wrist")
},
{
jointName: "RightWrist",
controller: Controller.createInputController("Spatial", "joint_R_wrist")
}
];
hands = [ hands = [
{ {
jointName: "LeftHand", jointName: "LeftHand",
@ -239,11 +261,6 @@ var leapHands = (function () {
} }
]; ];
wrists = [
{ controller: Controller.createInputController("Spatial", "joint_L_wrist") },
{ controller: Controller.createInputController("Spatial", "joint_R_wrist") }
];
// The Leap controller's first joint is the hand-metacarpal joint but this joint's data is not used because it's too // The Leap controller's first joint is the hand-metacarpal joint but this joint's data is not used because it's too
// dependent on the model skeleton exactly matching the Leap skeleton; using just the second and subsequent joints // dependent on the model skeleton exactly matching the Leap skeleton; using just the second and subsequent joints
// seems to work better over all. // seems to work better over all.
@ -306,6 +323,8 @@ var leapHands = (function () {
setIsOnHMD(); setIsOnHMD();
settingsTimer = Script.setInterval(checkSettings, 2000); settingsTimer = Script.setInterval(checkSettings, 2000);
calibrationStatus = UNCALIBRATED;
} }
function moveHands() { function moveHands() {
@ -314,6 +333,7 @@ var leapHands = (function () {
j, j,
side, side,
handOffset, handOffset,
wristOffset,
handRotation, handRotation,
locRotation, locRotation,
cameraOrientation, cameraOrientation,
@ -330,10 +350,18 @@ var leapHands = (function () {
} }
// Hand position ... // Hand position ...
handOffset = hands[h].controller.getAbsTranslation();
handRotation = hands[h].controller.getAbsRotation();
if (isOnHMD) { if (isOnHMD) {
// Adjust to control wrist position if "hand" joint is at wrist ...
if (!hasHandAndWristJoints) {
wristOffset = Vec3.multiplyQbyV(handRotation, handToWristOffset[h]);
handOffset = Vec3.sum(handOffset, wristOffset);
}
// Hand offset in camera coordinates ... // Hand offset in camera coordinates ...
handOffset = hands[h].controller.getAbsTranslation();
handOffset = { handOffset = {
x: hands[h].zeroPosition.x - handOffset.x, x: hands[h].zeroPosition.x - handOffset.x,
y: hands[h].zeroPosition.y - handOffset.z, y: hands[h].zeroPosition.y - handOffset.z,
@ -353,7 +381,6 @@ var leapHands = (function () {
handOffset.x = -handOffset.x; handOffset.x = -handOffset.x;
// Hand rotation in camera coordinates ... // Hand rotation in camera coordinates ...
handRotation = wrists[h].controller.getAbsRotation();
handRotation = { handRotation = {
x: handRotation.z, x: handRotation.z,
y: handRotation.y, y: handRotation.y,
@ -361,6 +388,7 @@ var leapHands = (function () {
w: handRotation.w w: handRotation.w
}; };
// Hand rotation in avatar coordinates ...
if (h === 0) { if (h === 0) {
handRotation.x = -handRotation.x; handRotation.x = -handRotation.x;
handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation);
@ -371,7 +399,6 @@ var leapHands = (function () {
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 0, z: 1 }), handRotation); handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 0, z: 1 }), handRotation);
} }
// Hand rotation in avatar coordinates ...
cameraOrientation.x = -cameraOrientation.x; cameraOrientation.x = -cameraOrientation.x;
cameraOrientation.z = -cameraOrientation.z; cameraOrientation.z = -cameraOrientation.z;
handRotation = Quat.multiply(cameraOrientation, handRotation); handRotation = Quat.multiply(cameraOrientation, handRotation);
@ -379,14 +406,20 @@ var leapHands = (function () {
} else { } else {
handOffset = hands[h].controller.getAbsTranslation(); // Adjust to control wrist position if "hand" joint is at wrist ...
if (!hasHandAndWristJoints) {
wristOffset = Vec3.multiplyQbyV(handRotation, handToWristOffset[h]);
handOffset = Vec3.sum(handOffset, wristOffset);
}
// Hand offset in camera coordinates ...
handOffset = { handOffset = {
x: -handOffset.x, x: -handOffset.x,
y: hands[h].zeroPosition.y + handOffset.y, y: hands[h].zeroPosition.y + handOffset.y,
z: hands[h].zeroPosition.z - handOffset.z z: hands[h].zeroPosition.z - handOffset.z
}; };
handRotation = wrists[h].controller.getAbsRotation(); // Hand rotation in camera coordinates ...
handRotation = { handRotation = {
x: handRotation.z, x: handRotation.z,
y: handRotation.y, y: handRotation.y,
@ -394,6 +427,7 @@ var leapHands = (function () {
w: handRotation.w w: handRotation.w
}; };
// Hand rotation in avatar coordinates ...
if (h === 0) { if (h === 0) {
handRotation.x = -handRotation.x; handRotation.x = -handRotation.x;
handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }),
@ -405,9 +439,10 @@ var leapHands = (function () {
} }
} }
// Set hand position and orientation ...
MyAvatar.setJointModelPositionAndOrientation(hands[h].jointName, handOffset, handRotation, true); MyAvatar.setJointModelPositionAndOrientation(hands[h].jointName, handOffset, handRotation, true);
// Finger joints ... // Set finger joints ...
for (i = 0; i < NUM_FINGERS; i += 1) { for (i = 0; i < NUM_FINGERS; i += 1) {
for (j = 0; j < NUM_FINGER_JOINTS; j += 1) { for (j = 0; j < NUM_FINGER_JOINTS; j += 1) {
if (fingers[h][i][j].controller !== null) { if (fingers[h][i][j].controller !== null) {

View file

@ -167,6 +167,51 @@ var clipboardPreview = Overlays.addOverlay("clipboard", {
visible: true visible: true
}); });
// Demonstrate retrieving overlay properties
print("Text overlay text property value =\n" + Overlays.getProperty(text, "text"));
print("Text overlay alpha =\n" + Overlays.getProperty(text, "alpha"));
print("Text overlay visible =\n" + Overlays.getProperty(text, "visible"));
print("Text overlay font size =\n" + Overlays.getProperty(text, "font").size);
print("Text overlay anchor =\n" + Overlays.getProperty(text, "anchor"));
print("Text overlay unknown property value =\n" + Overlays.getProperty(text, "unknown")); // value = undefined
var sliderBounds = Overlays.getProperty(slider, "bounds");
print("Slider overlay bounds =\n"
+ "x: " + sliderBounds.x + "\n"
+ "y: " + sliderBounds.y + "\n"
+ "width: " + sliderBounds.width + "\n"
+ "height: " + sliderBounds.height
);
var cubePosition = Overlays.getProperty(cube, "position");
print("Cube overlay position =\n"
+ "x: " + cubePosition.x + "\n"
+ "y: " + cubePosition.y + "\n"
+ "z: " + cubePosition.z
);
var cubeColor = Overlays.getProperty(cube, "color");
print("Cube overlay color =\n"
+ "red: " + cubeColor.red + "\n"
+ "green: " + cubeColor.green + "\n"
+ "blue: " + cubeColor.blue
);
// This model overlay example causes intermittent crashes in NetworkGeometry::setTextureWithNameToURL()
//var modelOverlayProperties = {
// textures: {
// filename1: HIFI_PUBLIC_BUCKET + "images/testing-swatches.svg",
// filename2: HIFI_PUBLIC_BUCKET + "images/hifi-interface-tools.svg"
// }
//}
//var modelOverlay = Overlays.addOverlay("model", modelOverlayProperties);
//var textures = Overlays.getProperty(modelOverlay, "textures");
//var textureValues = "";
//for (key in textures) {
// textureValues += "\n" + key + ": " + textures[key];
//}
//print("Model overlay textures =" + textureValues);
//Overlays.deleteOverlay(modelOverlay);
print("Unknown overlay property =\n" + Overlays.getProperty(1000, "text")); // value = undefined
// When our script shuts down, we should clean up all of our overlays // When our script shuts down, we should clean up all of our overlays
function scriptEnding() { function scriptEnding() {

View file

@ -3906,7 +3906,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
connect(scriptEngine, SIGNAL(loadScript(const QString&, bool)), this, SLOT(loadScript(const QString&, bool))); connect(scriptEngine, SIGNAL(loadScript(const QString&, bool)), this, SLOT(loadScript(const QString&, bool)));
scriptEngine->registerGlobalObject("Overlays", &_overlays); scriptEngine->registerGlobalObject("Overlays", &_overlays);
qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue, RayToOverlayIntersectionResultFromScriptValue); qScriptRegisterMetaType(scriptEngine, OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue);
qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue,
RayToOverlayIntersectionResultFromScriptValue);
QScriptValue windowValue = scriptEngine->registerGlobalObject("Window", WindowScriptingInterface::getInstance()); QScriptValue windowValue = scriptEngine->registerGlobalObject("Window", WindowScriptingInterface::getInstance());
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,

View file

@ -70,8 +70,8 @@ Leapmotion::Leapmotion() :
std::vector< Semantic > rootBones; std::vector< Semantic > rootBones;
rootBones.push_back("elbow"); rootBones.push_back("elbow");
rootBones.push_back("hand");
rootBones.push_back("wrist"); rootBones.push_back("wrist");
rootBones.push_back("hand");
std::vector< Semantic > fingers; std::vector< Semantic > fingers;
fingers.push_back("thumb"); fingers.push_back("thumb");

View file

@ -537,7 +537,7 @@ void Model::renderSetup(RenderArgs* args) {
} }
} }
if (!_meshGroupsKnown) { if (!_meshGroupsKnown && isLoadedWithTextures()) {
segregateMeshGroups(); segregateMeshGroups();
} }
} }
@ -628,7 +628,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args); opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, args);
opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args);
opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args); opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, args);
opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, args); opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, args);
// render translucent meshes afterwards // render translucent meshes afterwards
//Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true); //Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true);
@ -649,7 +649,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, false, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, false, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, false, true, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, true, true, true, args);
GLBATCH(glDisable)(GL_ALPHA_TEST); GLBATCH(glDisable)(GL_ALPHA_TEST);
GLBATCH(glEnable)(GL_BLEND); GLBATCH(glEnable)(GL_BLEND);
@ -673,7 +673,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, false, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, false, args);
translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, false, true, args); translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, true, true, true, args);
} }
GLBATCH(glDepthMask)(true); GLBATCH(glDepthMask)(true);

View file

@ -118,6 +118,32 @@ void Base3DOverlay::setProperties(const QScriptValue& properties) {
} }
} }
QScriptValue Base3DOverlay::getProperty(const QString& property) {
if (property == "position" || property == "start" || property == "p1" || property == "point") {
return vec3toScriptValue(_scriptEngine, _position);
}
if (property == "lineWidth") {
return _lineWidth;
}
if (property == "rotation") {
return quatToScriptValue(_scriptEngine, _rotation);
}
if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filed") {
return _isSolid;
}
if (property == "isWire" || property == "wire") {
return !_isSolid;
}
if (property == "isDashedLine" || property == "dashed") {
return _isDashedLine;
}
if (property == "ignoreRayIntersection") {
return _ignoreRayIntersection;
}
return Overlay::getProperty(property);
}
bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face) const { float& distance, BoxFace& face) const {
return false; return false;

View file

@ -45,6 +45,7 @@ public:
void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; } void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; }
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;

View file

@ -157,6 +157,23 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
} }
} }
QScriptValue BillboardOverlay::getProperty(const QString& property) {
if (property == "url") {
return _url;
}
if (property == "subImage") {
return qRectToScriptValue(_scriptEngine, _fromImage);
}
if (property == "scale") {
return _scale;
}
if (property == "isFacingAvatar") {
return _isFacingAvatar;
}
return Base3DOverlay::getProperty(property);
}
void BillboardOverlay::setURL(const QString& url) { void BillboardOverlay::setURL(const QString& url) {
setBillboardURL(url); setBillboardURL(url);
} }

View file

@ -32,6 +32,7 @@ public:
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; } void setClipFromSource(const QRect& bounds) { _fromImage = bounds; }
virtual QScriptValue getProperty(const QString& property);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;

View file

@ -299,6 +299,45 @@ void Circle3DOverlay::setProperties(const QScriptValue &properties) {
} }
} }
QScriptValue Circle3DOverlay::getProperty(const QString& property) {
if (property == "startAt") {
return _startAt;
}
if (property == "endAt") {
return _endAt;
}
if (property == "outerRadius") {
return _outerRadius;
}
if (property == "innerRadius") {
return _innerRadius;
}
if (property == "hasTickMarks") {
return _hasTickMarks;
}
if (property == "majorTickMarksAngle") {
return _majorTickMarksAngle;
}
if (property == "minorTickMarksAngle") {
return _minorTickMarksAngle;
}
if (property == "majorTickMarksLength") {
return _majorTickMarksLength;
}
if (property == "minorTickMarksLength") {
return _minorTickMarksLength;
}
if (property == "majorTickMarksColor") {
return xColorToScriptValue(_scriptEngine, _majorTickMarksColor);
}
if (property == "minorTickMarksColor") {
return xColorToScriptValue(_scriptEngine, _minorTickMarksColor);
}
return Planar3DOverlay::getProperty(property);
}
bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin,
const glm::vec3& direction, float& distance, BoxFace& face) const { const glm::vec3& direction, float& distance, BoxFace& face) const {

View file

@ -21,6 +21,7 @@ public:
~Circle3DOverlay(); ~Circle3DOverlay();
virtual void render(RenderArgs* args); virtual void render(RenderArgs* args);
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
float getStartAt() const { return _startAt; } float getStartAt() const { return _startAt; }
float getEndAt() const { return _endAt; } float getEndAt() const { return _endAt; }

View file

@ -116,3 +116,14 @@ void Grid3DOverlay::setProperties(const QScriptValue& properties) {
_majorGridEvery = properties.property("majorGridEvery").toVariant().toInt(); _majorGridEvery = properties.property("majorGridEvery").toVariant().toInt();
} }
} }
QScriptValue Grid3DOverlay::getProperty(const QString& property) {
if (property == "minorGridWidth") {
return _minorGridWidth;
}
if (property == "majorGridEvery") {
return _majorGridEvery;
}
return Base3DOverlay::getProperty(property);
}

View file

@ -33,6 +33,7 @@ public:
virtual void render(RenderArgs* args); virtual void render(RenderArgs* args);
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
private: private:
float _minorGridWidth; float _minorGridWidth;

View file

@ -151,4 +151,13 @@ void ImageOverlay::setProperties(const QScriptValue& properties) {
} }
} }
QScriptValue ImageOverlay::getProperty(const QString& property) {
if (property == "subImage") {
return qRectToScriptValue(_scriptEngine, _fromImage);
}
if (property == "imageURL") {
return _imageURL.toString();
}
return Overlay2D::getProperty(property);
}

View file

@ -44,6 +44,7 @@ public:
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; _wantClipFromImage = true; } void setClipFromSource(const QRect& bounds) { _fromImage = bounds; _wantClipFromImage = true; }
void setImageURL(const QUrl& url); void setImageURL(const QUrl& url);
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
private slots: private slots:
void replyFinished(); // we actually want to hide this... void replyFinished(); // we actually want to hide this...

View file

@ -79,3 +79,11 @@ void Line3DOverlay::setProperties(const QScriptValue& properties) {
} }
} }
} }
QScriptValue Line3DOverlay::getProperty(const QString& property) {
if (property == "end" || property == "endPoint" || property == "p2") {
return vec3toScriptValue(_scriptEngine, _end);
}
return Base3DOverlay::getProperty(property);
}

View file

@ -28,6 +28,7 @@ public:
void setEnd(const glm::vec3& end) { _end = end; } void setEnd(const glm::vec3& end) { _end = end; }
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
protected: protected:
glm::vec3 _end; glm::vec3 _end;

View file

@ -103,3 +103,14 @@ void LocalVoxelsOverlay::setProperties(const QScriptValue &properties) {
} }
} }
QScriptValue LocalVoxelsOverlay::getProperty(const QString& property) {
if (property == "scale") {
return vec3toScriptValue(_scriptEngine, getDimensions());
}
if (property == "name") {
return _treeName;
}
return Volume3DOverlay::getProperty(property);
}

View file

@ -38,6 +38,7 @@ public:
virtual void render(RenderArgs* args); virtual void render(RenderArgs* args);
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
private: private:
static QMap<QString, WeakVoxelSystemPointer> _voxelSystemMap; // treeName/voxelSystem static QMap<QString, WeakVoxelSystemPointer> _voxelSystemMap; // treeName/voxelSystem

View file

@ -14,6 +14,7 @@
ModelOverlay::ModelOverlay() ModelOverlay::ModelOverlay()
: _model(), : _model(),
_modelTextures(QVariantMap()),
_scale(1.0f), _scale(1.0f),
_updateModel(false) _updateModel(false)
{ {
@ -114,6 +115,8 @@ void ModelOverlay::setProperties(const QScriptValue &properties) {
QMetaObject::invokeMethod(&_model, "setTextureWithNameToURL", Qt::AutoConnection, QMetaObject::invokeMethod(&_model, "setTextureWithNameToURL", Qt::AutoConnection,
Q_ARG(const QString&, key), Q_ARG(const QString&, key),
Q_ARG(const QUrl&, newTextureURL)); Q_ARG(const QUrl&, newTextureURL));
_modelTextures[key] = newTextureURL; // Keep local track of textures for getProperty()
} }
} }
@ -122,6 +125,34 @@ void ModelOverlay::setProperties(const QScriptValue &properties) {
} }
} }
QScriptValue ModelOverlay::getProperty(const QString& property) {
if (property == "url") {
return _url.toString();
}
if (property == "scale") {
return _scale;
}
if (property == "rotation") {
return quatToScriptValue(_scriptEngine, _rotation);
}
if (property == "dimensions") {
return vec3toScriptValue(_scriptEngine, _model.getScaleToFitDimensions());
}
if (property == "textures") {
if (_modelTextures.size() > 0) {
QScriptValue textures = _scriptEngine->newObject();
foreach(const QString& key, _modelTextures.keys()) {
textures.setProperty(key, _modelTextures[key].toString());
}
return textures;
} else {
return QScriptValue();
}
}
return Base3DOverlay::getProperty(property);
}
bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face) const { float& distance, BoxFace& face) const {

View file

@ -24,6 +24,7 @@ public:
virtual void update(float deltatime); virtual void update(float deltatime);
virtual void render(RenderArgs* args); virtual void render(RenderArgs* args);
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face, QString& extraInfo) const; float& distance, BoxFace& face, QString& extraInfo) const;
@ -31,6 +32,7 @@ public:
private: private:
Model _model; Model _model;
QVariantMap _modelTextures;
QUrl _url; QUrl _url;
glm::quat _rotation; glm::quat _rotation;

View file

@ -39,8 +39,9 @@ Overlay::Overlay() :
{ {
} }
void Overlay::init(QGLWidget* parent) { void Overlay::init(QGLWidget* parent, QScriptEngine* scriptEngine) {
_parent = parent; _parent = parent;
_scriptEngine = scriptEngine;
} }
@ -104,6 +105,44 @@ void Overlay::setProperties(const QScriptValue& properties) {
} }
} }
QScriptValue Overlay::getProperty(const QString& property) {
if (property == "color") {
return xColorToScriptValue(_scriptEngine, _color);
}
if (property == "alpha") {
return _alpha;
}
if (property == "glowLevel") {
return _glowLevel;
}
if (property == "pulseMax") {
return _pulseMax;
}
if (property == "pulseMin") {
return _pulseMin;
}
if (property == "pulsePeriod") {
return _pulsePeriod;
}
if (property == "glowLevelPulse") {
return _glowLevelPulse;
}
if (property == "alphaPulse") {
return _alphaPulse;
}
if (property == "colorPulse") {
return _colorPulse;
}
if (property == "visible") {
return _visible;
}
if (property == "anchor") {
return _anchor == MY_AVATAR ? "MyAvatar" : "";
}
return QScriptValue();
}
xColor Overlay::getColor() { xColor Overlay::getColor() {
if (_colorPulse == 0.0f) { if (_colorPulse == 0.0f) {
return _color; return _color;

View file

@ -19,6 +19,7 @@
#include <QScriptValue> #include <QScriptValue>
#include <QString> #include <QString>
#include <RegisteredMetaTypes.h>
#include <SharedUtil.h> // for xColor #include <SharedUtil.h> // for xColor
#include <RenderArgs.h> #include <RenderArgs.h>
@ -36,7 +37,7 @@ public:
Overlay(); Overlay();
~Overlay(); ~Overlay();
void init(QGLWidget* parent); void init(QGLWidget* parent, QScriptEngine* scriptEngine);
virtual void update(float deltatime) {} virtual void update(float deltatime) {}
virtual void render(RenderArgs* args) = 0; virtual void render(RenderArgs* args) = 0;
@ -77,6 +78,7 @@ public:
void setAlphaPulse(float value) { _alphaPulse = value; } void setAlphaPulse(float value) { _alphaPulse = value; }
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
protected: protected:
float updatePulse(); float updatePulse();
@ -100,6 +102,8 @@ protected:
xColor _color; xColor _color;
bool _visible; // should the overlay be drawn at all bool _visible; // should the overlay be drawn at all
Anchor _anchor; Anchor _anchor;
QScriptEngine* _scriptEngine;
}; };

View file

@ -64,3 +64,23 @@ void Overlay2D::setProperties(const QScriptValue& properties) {
//qDebug() << "set bounds to " << getBounds(); //qDebug() << "set bounds to " << getBounds();
} }
} }
QScriptValue Overlay2D::getProperty(const QString& property) {
if (property == "bounds") {
return qRectToScriptValue(_scriptEngine, _bounds);
}
if (property == "x") {
return _bounds.x();
}
if (property == "y") {
return _bounds.y();
}
if (property == "width") {
return _bounds.width();
}
if (property == "height") {
return _bounds.height();
}
return Overlay::getProperty(property);
}

View file

@ -47,6 +47,7 @@ public:
void setBounds(const QRect& bounds) { _bounds = bounds; } void setBounds(const QRect& bounds) { _bounds = bounds; }
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
protected: protected:
QRect _bounds; // where on the screen to draw QRect _bounds; // where on the screen to draw

View file

@ -12,6 +12,7 @@
#include <typeinfo> #include <typeinfo>
#include <Application.h> #include <Application.h>
#include <Menu.h> #include <Menu.h>
#include <QScriptValueIterator>
#include "BillboardOverlay.h" #include "BillboardOverlay.h"
#include "Circle3DOverlay.h" #include "Circle3DOverlay.h"
@ -56,6 +57,7 @@ Overlays::~Overlays() {
void Overlays::init(QGLWidget* parent) { void Overlays::init(QGLWidget* parent) {
_parent = parent; _parent = parent;
_scriptEngine = new QScriptEngine();
} }
void Overlays::update(float deltatime) { void Overlays::update(float deltatime) {
@ -180,7 +182,7 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
} }
unsigned int Overlays::addOverlay(Overlay* overlay) { unsigned int Overlays::addOverlay(Overlay* overlay) {
overlay->init(_parent); overlay->init(_parent, _scriptEngine);
QWriteLocker lock(&_lock); QWriteLocker lock(&_lock);
unsigned int thisID = _nextOverlayID; unsigned int thisID = _nextOverlayID;
@ -242,6 +244,51 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
return 0; // not found return 0; // not found
} }
OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& property) {
OverlayPropertyResult result;
Overlay* thisOverlay = NULL;
QReadLocker lock(&_lock);
if (_overlays2D.contains(id)) {
thisOverlay = _overlays2D[id];
} else if (_overlays3D.contains(id)) {
thisOverlay = _overlays3D[id];
}
if (thisOverlay) {
result.value = thisOverlay->getProperty(property);
}
return result;
}
OverlayPropertyResult::OverlayPropertyResult() :
value(QScriptValue())
{
}
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& result)
{
if (!result.value.isValid()) {
return QScriptValue::UndefinedValue;
}
QScriptValue object = engine->newObject();
if (result.value.isObject()) {
QScriptValueIterator it(result.value);
while (it.hasNext()) {
it.next();
object.setProperty(it.name(), QScriptValue(it.value().toString()));
}
} else {
object = result.value;
}
return object;
}
void OverlayPropertyResultFromScriptValue(const QScriptValue& value, OverlayPropertyResult& result)
{
result.value = value;
}
RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray) { RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray) {
float bestDistance = std::numeric_limits<float>::max(); float bestDistance = std::numeric_limits<float>::max();
RayToOverlayIntersectionResult result; RayToOverlayIntersectionResult result;

View file

@ -16,6 +16,17 @@
#include "Overlay.h" #include "Overlay.h"
class OverlayPropertyResult {
public:
OverlayPropertyResult();
QScriptValue value;
};
Q_DECLARE_METATYPE(OverlayPropertyResult);
QScriptValue OverlayPropertyResultToScriptValue(QScriptEngine* engine, const OverlayPropertyResult& value);
void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPropertyResult& value);
class RayToOverlayIntersectionResult { class RayToOverlayIntersectionResult {
public: public:
RayToOverlayIntersectionResult(); RayToOverlayIntersectionResult();
@ -27,6 +38,7 @@ public:
QString extraInfo; QString extraInfo;
}; };
Q_DECLARE_METATYPE(RayToOverlayIntersectionResult); Q_DECLARE_METATYPE(RayToOverlayIntersectionResult);
QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value); QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value);
@ -59,6 +71,9 @@ public slots:
/// returns the top most 2D overlay at the screen point, or 0 if not overlay at that point /// returns the top most 2D overlay at the screen point, or 0 if not overlay at that point
unsigned int getOverlayAtPoint(const glm::vec2& point); unsigned int getOverlayAtPoint(const glm::vec2& point);
/// returns the value of specified property, or null if there is no such property
OverlayPropertyResult getProperty(unsigned int id, const QString& property);
/// returns details about the closest 3D Overlay hit by the pick ray /// returns details about the closest 3D Overlay hit by the pick ray
RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray); RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray);
@ -77,6 +92,7 @@ private:
QGLWidget* _parent; QGLWidget* _parent;
QReadWriteLock _lock; QReadWriteLock _lock;
QReadWriteLock _deleteLock; QReadWriteLock _deleteLock;
QScriptEngine* _scriptEngine;
}; };

View file

@ -77,6 +77,14 @@ void Planar3DOverlay::setProperties(const QScriptValue& properties) {
} }
} }
QScriptValue Planar3DOverlay::getProperty(const QString& property) {
if (property == "dimensions" || property == "scale" || property == "size") {
return vec2toScriptValue(_scriptEngine, _dimensions);
}
return Base3DOverlay::getProperty(property);
}
bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face) const { float& distance, BoxFace& face) const {

View file

@ -36,6 +36,7 @@ public:
void setDimensions(const glm::vec2& value) { _dimensions = value; } void setDimensions(const glm::vec2& value) { _dimensions = value; }
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;

View file

@ -180,9 +180,38 @@ void Text3DOverlay::setProperties(const QScriptValue& properties) {
} }
QScriptValue Text3DOverlay::getProperty(const QString& property) {
if (property == "text") {
return _text;
}
if (property == "backgroundColor") {
return xColorToScriptValue(_scriptEngine, _backgroundColor);
}
if (property == "lineHeight") {
return _lineHeight;
}
if (property == "leftMargin") {
return _leftMargin;
}
if (property == "topMargin") {
return _topMargin;
}
if (property == "rightMargin") {
return _rightMargin;
}
if (property == "bottomMargin") {
return _bottomMargin;
}
if (property == "isFacingAvatar") {
return _isFacingAvatar;
}
return Planar3DOverlay::getProperty(property);
}
float Text3DOverlay::textWidth(const QString& text) const { float Text3DOverlay::textWidth(const QString& text) const {
QFont font(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); // Same font properties as render() QFont font(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); // Same font properties as render()
QFontMetrics fontMetrics(font); QFontMetrics fontMetrics(font);
float scaleFactor = _lineHeight * LINE_SCALE_RATIO / (float)FIXED_FONT_POINT_SIZE; float scaleFactor = _lineHeight * LINE_SCALE_RATIO / (float)FIXED_FONT_POINT_SIZE;
return scaleFactor * (float)fontMetrics.width(qPrintable(text)); return scaleFactor * (float)fontMetrics.width(qPrintable(text));
} }

View file

@ -47,6 +47,7 @@ public:
void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; } void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; }
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
float textWidth(const QString& text) const; // Meters float textWidth(const QString& text) const; // Meters

View file

@ -124,6 +124,28 @@ void TextOverlay::setProperties(const QScriptValue& properties) {
} }
} }
QScriptValue TextOverlay::getProperty(const QString& property) {
if (property == "font") {
QScriptValue font = _scriptEngine->newObject();
font.setProperty("size", _fontSize);
return font;
}
if (property == "text") {
return _text;
}
if (property == "backgroundColor") {
return xColorToScriptValue(_scriptEngine, _backgroundColor);
}
if (property == "leftMargin") {
return _leftMargin;
}
if (property == "topMargin") {
return _topMargin;
}
return Overlay2D::getProperty(property);
}
float TextOverlay::textWidth(const QString& text) const { float TextOverlay::textWidth(const QString& text) const {
QFont font(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); // Same font properties as render() QFont font(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); // Same font properties as render()

View file

@ -53,6 +53,7 @@ public:
void setFontSize(int fontSize) { _fontSize = fontSize; } void setFontSize(int fontSize) { _fontSize = fontSize; }
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
float textWidth(const QString& text) const; // Pixels float textWidth(const QString& text) const; // Pixels

View file

@ -85,6 +85,14 @@ void Volume3DOverlay::setProperties(const QScriptValue& properties) {
} }
} }
QScriptValue Volume3DOverlay::getProperty(const QString& property) {
if (property == "dimensions" || property == "scale" || property == "size") {
return vec3toScriptValue(_scriptEngine, _dimensions);
}
return Base3DOverlay::getProperty(property);
}
bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float& distance, BoxFace& face) const { float& distance, BoxFace& face) const {

View file

@ -38,6 +38,7 @@ public:
void setDimensions(const glm::vec3& value) { _dimensions = value; } void setDimensions(const glm::vec3& value) { _dimensions = value; }
virtual void setProperties(const QScriptValue& properties); virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;

View file

@ -28,6 +28,7 @@ const float EntityItem::DEFAULT_GLOW_LEVEL = 0.0f;
const float EntityItem::DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const float EntityItem::DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
const float EntityItem::DEFAULT_MASS = 1.0f; const float EntityItem::DEFAULT_MASS = 1.0f;
const float EntityItem::DEFAULT_LIFETIME = EntityItem::IMMORTAL; const float EntityItem::DEFAULT_LIFETIME = EntityItem::IMMORTAL;
const QString EntityItem::DEFAULT_USER_DATA = QString("");
const float EntityItem::DEFAULT_DAMPING = 0.5f; const float EntityItem::DEFAULT_DAMPING = 0.5f;
const glm::vec3 EntityItem::NO_VELOCITY = glm::vec3(0, 0, 0); const glm::vec3 EntityItem::NO_VELOCITY = glm::vec3(0, 0, 0);
const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 1000.0f) / (float)TREE_SCALE; // really small: 1mm/second const float EntityItem::EPSILON_VELOCITY_LENGTH = (1.0f / 1000.0f) / (float)TREE_SCALE; // really small: 1mm/second
@ -71,6 +72,7 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) {
_gravity = DEFAULT_GRAVITY; _gravity = DEFAULT_GRAVITY;
_damping = DEFAULT_DAMPING; _damping = DEFAULT_DAMPING;
_lifetime = DEFAULT_LIFETIME; _lifetime = DEFAULT_LIFETIME;
_userData = DEFAULT_USER_DATA;
_registrationPoint = DEFAULT_REGISTRATION_POINT; _registrationPoint = DEFAULT_REGISTRATION_POINT;
_angularVelocity = DEFAULT_ANGULAR_VELOCITY; _angularVelocity = DEFAULT_ANGULAR_VELOCITY;
_angularDamping = DEFAULT_ANGULAR_DAMPING; _angularDamping = DEFAULT_ANGULAR_DAMPING;
@ -123,6 +125,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_IGNORE_FOR_COLLISIONS; requestedProperties += PROP_IGNORE_FOR_COLLISIONS;
requestedProperties += PROP_COLLISIONS_WILL_MOVE; requestedProperties += PROP_COLLISIONS_WILL_MOVE;
requestedProperties += PROP_LOCKED; requestedProperties += PROP_LOCKED;
requestedProperties += PROP_USER_DATA;
return requestedProperties; return requestedProperties;
} }
@ -239,6 +242,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, getIgnoreForCollisions()); APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, appendValue, getIgnoreForCollisions());
APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove());
APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, getLocked()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, getLocked());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, getUserData());
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
requestedProperties, requestedProperties,
@ -502,6 +506,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, _ignoreForCollisions); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, _ignoreForCollisions);
READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, _collisionsWillMove); READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, _collisionsWillMove);
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked);
READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA,setUserData);
if (wantDebug) { if (wantDebug) {
qDebug() << " readEntityDataFromBuffer() _registrationPoint:" << _registrationPoint; qDebug() << " readEntityDataFromBuffer() _registrationPoint:" << _registrationPoint;
@ -758,6 +763,7 @@ EntityItemProperties EntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignoreForCollisions, getIgnoreForCollisions); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignoreForCollisions, getIgnoreForCollisions);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData);
properties._defaultSettings = false; properties._defaultSettings = false;
@ -794,6 +800,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties, bool forc
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, setIgnoreForCollisions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, setIgnoreForCollisions);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, setCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, setCollisionsWillMove);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData);
if (somethingChanged) { if (somethingChanged) {
somethingChangedNotification(); // notify derived classes that something has changed somethingChangedNotification(); // notify derived classes that something has changed

View file

@ -252,6 +252,10 @@ public:
bool getLocked() const { return _locked; } bool getLocked() const { return _locked; }
void setLocked(bool value) { _locked = value; } void setLocked(bool value) { _locked = value; }
static const QString DEFAULT_USER_DATA;
const QString& getUserData() const { return _userData; }
void setUserData(const QString& value) { _userData = value; }
// TODO: We need to get rid of these users of getRadius()... // TODO: We need to get rid of these users of getRadius()...
float getRadius() const; float getRadius() const;
@ -292,6 +296,7 @@ protected:
bool _ignoreForCollisions; bool _ignoreForCollisions;
bool _collisionsWillMove; bool _collisionsWillMove;
bool _locked; bool _locked;
QString _userData;
// NOTE: Radius support is obsolete, but these private helper functions are available for this class to // NOTE: Radius support is obsolete, but these private helper functions are available for this class to
// parse old data streams // parse old data streams

View file

@ -37,6 +37,7 @@ EntityItemProperties::EntityItemProperties() :
_gravity(EntityItem::DEFAULT_GRAVITY), _gravity(EntityItem::DEFAULT_GRAVITY),
_damping(EntityItem::DEFAULT_DAMPING), _damping(EntityItem::DEFAULT_DAMPING),
_lifetime(EntityItem::DEFAULT_LIFETIME), _lifetime(EntityItem::DEFAULT_LIFETIME),
_userData(EntityItem::DEFAULT_USER_DATA),
_script(EntityItem::DEFAULT_SCRIPT), _script(EntityItem::DEFAULT_SCRIPT),
_registrationPoint(EntityItem::DEFAULT_REGISTRATION_POINT), _registrationPoint(EntityItem::DEFAULT_REGISTRATION_POINT),
_angularVelocity(EntityItem::DEFAULT_ANGULAR_VELOCITY), _angularVelocity(EntityItem::DEFAULT_ANGULAR_VELOCITY),
@ -53,6 +54,7 @@ EntityItemProperties::EntityItemProperties() :
_gravityChanged(false), _gravityChanged(false),
_dampingChanged(false), _dampingChanged(false),
_lifetimeChanged(false), _lifetimeChanged(false),
_userDataChanged(false),
_scriptChanged(false), _scriptChanged(false),
_registrationPointChanged(false), _registrationPointChanged(false),
_angularVelocityChanged(false), _angularVelocityChanged(false),
@ -223,6 +225,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_CUTOFF, cutoff); CHECK_PROPERTY_CHANGE(PROP_CUTOFF, cutoff);
CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked); CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked);
CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures); CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures);
CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData);
return changedProperties; return changedProperties;
} }
@ -276,6 +279,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
COPY_PROPERTY_TO_QSCRIPTVALUE(cutoff); COPY_PROPERTY_TO_QSCRIPTVALUE(cutoff);
COPY_PROPERTY_TO_QSCRIPTVALUE(locked); COPY_PROPERTY_TO_QSCRIPTVALUE(locked);
COPY_PROPERTY_TO_QSCRIPTVALUE(textures); COPY_PROPERTY_TO_QSCRIPTVALUE(textures);
COPY_PROPERTY_TO_QSCRIPTVALUE(userData);
// Sitting properties support // Sitting properties support
QScriptValue sittingPoints = engine->newObject(); QScriptValue sittingPoints = engine->newObject();
@ -350,6 +354,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(cutoff, setCutoff); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(cutoff, setCutoff);
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(locked, setLocked); COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(locked, setLocked);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(textures, setTextures); COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(textures, setTextures);
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(userData, setUserData);
_lastEdited = usecTimestampNow(); _lastEdited = usecTimestampNow();
} }
@ -512,6 +517,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, properties.getLocked()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, properties.getLocked());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, properties.getTextures()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, appendValue, properties.getTextures());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, properties.getAnimationSettings()); APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, appendValue, properties.getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, properties.getUserData());
} }
if (propertyCount > 0) { if (propertyCount > 0) {
int endOfEntityItemData = packetData->getUncompressedByteOffset(); int endOfEntityItemData = packetData->getUncompressedByteOffset();
@ -722,6 +728,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_TEXTURES, setTextures); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_TEXTURES, setTextures);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, setAnimationSettings); READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, setAnimationSettings);
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_USER_DATA, setUserData);
return valid; return valid;
} }
@ -764,6 +771,7 @@ void EntityItemProperties::markAllChanged() {
_gravityChanged = true; _gravityChanged = true;
_dampingChanged = true; _dampingChanged = true;
_lifetimeChanged = true; _lifetimeChanged = true;
_userDataChanged = true;
_scriptChanged = true; _scriptChanged = true;
_registrationPointChanged = true; _registrationPointChanged = true;
_angularVelocityChanged = true; _angularVelocityChanged = true;

View file

@ -81,8 +81,9 @@ enum EntityPropertyList {
// used by Model entities // used by Model entities
PROP_TEXTURES, PROP_TEXTURES,
PROP_ANIMATION_SETTINGS, PROP_ANIMATION_SETTINGS,
PROP_USER_DATA,
PROP_LAST_ITEM = PROP_ANIMATION_SETTINGS PROP_LAST_ITEM = PROP_USER_DATA
}; };
typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags; typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
@ -159,6 +160,10 @@ public:
float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity
void setLifetime(float value) { _lifetime = value; _lifetimeChanged = true; } /// set the lifetime in seconds for the entity void setLifetime(float value) { _lifetime = value; _lifetimeChanged = true; } /// set the lifetime in seconds for the entity
const QString& getUserData() const { return _userData; }
void setUserData(const QString& value) { _userData = value; _userDataChanged = true; }
float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; }
quint64 getCreated() const { return _created; } quint64 getCreated() const { return _created; }
void setCreated(quint64 usecTime) { _created = usecTime; } void setCreated(quint64 usecTime) { _created = usecTime; }
@ -216,6 +221,7 @@ public:
bool gravityChanged() const { return _gravityChanged; } bool gravityChanged() const { return _gravityChanged; }
bool dampingChanged() const { return _dampingChanged; } bool dampingChanged() const { return _dampingChanged; }
bool lifetimeChanged() const { return _lifetimeChanged; } bool lifetimeChanged() const { return _lifetimeChanged; }
bool userDataChanged() const { return _userDataChanged; }
bool scriptChanged() const { return _scriptChanged; } bool scriptChanged() const { return _scriptChanged; }
bool dimensionsChanged() const { return _dimensionsChanged; } bool dimensionsChanged() const { return _dimensionsChanged; }
bool registrationPointChanged() const { return _registrationPointChanged; } bool registrationPointChanged() const { return _registrationPointChanged; }
@ -315,6 +321,7 @@ private:
glm::vec3 _gravity; glm::vec3 _gravity;
float _damping; float _damping;
float _lifetime; float _lifetime;
QString _userData;
QString _script; QString _script;
glm::vec3 _registrationPoint; glm::vec3 _registrationPoint;
glm::vec3 _angularVelocity; glm::vec3 _angularVelocity;
@ -331,6 +338,7 @@ private:
bool _gravityChanged; bool _gravityChanged;
bool _dampingChanged; bool _dampingChanged;
bool _lifetimeChanged; bool _lifetimeChanged;
bool _userDataChanged;
bool _scriptChanged; bool _scriptChanged;
bool _registrationPointChanged; bool _registrationPointChanged;
bool _angularVelocityChanged; bool _angularVelocityChanged;

View file

@ -115,8 +115,10 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying); READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, animationIsPlaying);
if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) { if (propertyFlags.getHasProperty(PROP_ANIMATION_PLAYING)) {
if (animationIsPlaying != getAnimationIsPlaying()) {
setAnimationIsPlaying(animationIsPlaying); setAnimationIsPlaying(animationIsPlaying);
} }
}
if (propertyFlags.getHasProperty(PROP_ANIMATION_FPS)) { if (propertyFlags.getHasProperty(PROP_ANIMATION_FPS)) {
setAnimationFPS(animationFPS); setAnimationFPS(animationFPS);
} }
@ -345,7 +347,6 @@ QVector<glm::quat> ModelEntityItem::getAnimationFrame() {
if (frameCount > 0) { if (frameCount > 0) {
int animationFrameIndex = (int)(glm::floor(getAnimationFrameIndex())) % frameCount; int animationFrameIndex = (int)(glm::floor(getAnimationFrameIndex())) % frameCount;
if (animationFrameIndex < 0 || animationFrameIndex > frameCount) { if (animationFrameIndex < 0 || animationFrameIndex > frameCount) {
animationFrameIndex = 0; animationFrameIndex = 0;
} }
@ -427,8 +428,10 @@ void ModelEntityItem::setAnimationSettings(const QString& value) {
if (settingsMap.contains("running")) { if (settingsMap.contains("running")) {
bool running = settingsMap["running"].toBool(); bool running = settingsMap["running"].toBool();
if (running != getAnimationIsPlaying()) {
setAnimationIsPlaying(running); setAnimationIsPlaying(running);
} }
}
if (settingsMap.contains("firstFrame")) { if (settingsMap.contains("firstFrame")) {
float firstFrame = settingsMap["firstFrame"].toFloat(); float firstFrame = settingsMap["firstFrame"].toFloat();

View file

@ -75,7 +75,7 @@ PacketVersion versionForPacketType(PacketType type) {
return 1; return 1;
case PacketTypeEntityAddOrEdit: case PacketTypeEntityAddOrEdit:
case PacketTypeEntityData: case PacketTypeEntityData:
return VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS; return VERSION_ENTITIES_HAVE_USER_DATA;
case PacketTypeEntityErase: case PacketTypeEntityErase:
return 2; return 2;
case PacketTypeAudioStreamStats: case PacketTypeAudioStreamStats:

View file

@ -125,6 +125,7 @@ const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3;
const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU; const PacketVersion VERSION_ENTITIES_HAS_FILE_BREAKS = VERSION_ENTITIES_SUPPORT_SPLIT_MTU;
const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4; const PacketVersion VERSION_ENTITIES_SUPPORT_DIMENSIONS = 4;
const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5; const PacketVersion VERSION_ENTITIES_MODELS_HAVE_ANIMATION_SETTINGS = 5;
const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6;
const PacketVersion VERSION_VOXELS_HAS_FILE_BREAKS = 1; const PacketVersion VERSION_VOXELS_HAS_FILE_BREAKS = 1;
#endif // hifi_PacketHeaders_h #endif // hifi_PacketHeaders_h

View file

@ -74,7 +74,7 @@ void Octree::recurseElementWithOperation(OctreeElement* element, RecurseOctreeOp
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex( = LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); "Octree::recurseElementWithOperation\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; qDebug() << "Octree::recurseElementWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return; return;
@ -96,7 +96,7 @@ void Octree::recurseElementWithPostOperation(OctreeElement* element, RecurseOctr
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex( = LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); "Octree::recurseElementWithPostOperation\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; qDebug() << "Octree::recurseElementWithPostOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return; return;
@ -126,7 +126,7 @@ void Octree::recurseElementWithOperationDistanceSorted(OctreeElement* element, R
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex( = LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); "Octree::recurseElementWithOperationDistanceSorted\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; qDebug() << "Octree::recurseElementWithOperationDistanceSorted() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return; return;
@ -167,7 +167,7 @@ bool Octree::recurseElementWithOperator(OctreeElement* element, RecurseOctreeOpe
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex( = LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!"); "Octree::recurseElementWithOperator\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; qDebug() << "Octree::recurseElementWithOperator() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return false; return false;
@ -231,8 +231,18 @@ OctreeElement* Octree::nodeForOctalCode(OctreeElement* ancestorElement,
} }
// returns the element created! // returns the element created!
OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach) { OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach, int recursionCount) {
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"Octree::createMissingElement\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "Octree::createMissingElement() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return lastParentElement;
}
int indexOfNewChild = branchIndexWithDescendant(lastParentElement->getOctalCode(), codeToReach); int indexOfNewChild = branchIndexWithDescendant(lastParentElement->getOctalCode(), codeToReach);
// If this parent element is a leaf, then you know the child path doesn't exist, so deal with // If this parent element is a leaf, then you know the child path doesn't exist, so deal with
// breaking up the leaf first, which will also create a child path // breaking up the leaf first, which will also create a child path
if (lastParentElement->requiresSplit()) { if (lastParentElement->requiresSplit()) {
@ -246,7 +256,7 @@ OctreeElement* Octree::createMissingElement(OctreeElement* lastParentElement, co
if (*lastParentElement->getChildAtIndex(indexOfNewChild)->getOctalCode() == *codeToReach) { if (*lastParentElement->getChildAtIndex(indexOfNewChild)->getOctalCode() == *codeToReach) {
return lastParentElement->getChildAtIndex(indexOfNewChild); return lastParentElement->getChildAtIndex(indexOfNewChild);
} else { } else {
return createMissingElement(lastParentElement->getChildAtIndex(indexOfNewChild), codeToReach); return createMissingElement(lastParentElement->getChildAtIndex(indexOfNewChild), codeToReach, recursionCount + 1);
} }
} }
@ -255,25 +265,20 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
int bytesLeftToRead = bytesAvailable; int bytesLeftToRead = bytesAvailable;
int bytesRead = 0; int bytesRead = 0;
bool wantDebug = false;
// give this destination element the child mask from the packet // give this destination element the child mask from the packet
const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF; const unsigned char ALL_CHILDREN_ASSUMED_TO_EXIST = 0xFF;
if ((size_t)bytesLeftToRead < sizeof(unsigned char)) { if ((size_t)bytesLeftToRead < sizeof(unsigned char)) {
if (wantDebug) {
qDebug() << "UNEXPECTED: readElementData() only had " << bytesLeftToRead << " bytes. " qDebug() << "UNEXPECTED: readElementData() only had " << bytesLeftToRead << " bytes. "
"Not enough for meaningful data."; "Not enough for meaningful data.";
}
return bytesAvailable; // assume we read the entire buffer... return bytesAvailable; // assume we read the entire buffer...
} }
if (destinationElement->getScale() < SCALE_AT_DANGEROUSLY_DEEP_RECURSION) { if (destinationElement->getScale() < SCALE_AT_DANGEROUSLY_DEEP_RECURSION) {
if (wantDebug) {
qDebug() << "UNEXPECTED: readElementData() destination element is unreasonably small [" qDebug() << "UNEXPECTED: readElementData() destination element is unreasonably small ["
<< destinationElement->getScale() * (float)TREE_SCALE << " meters] " << destinationElement->getScale() * (float)TREE_SCALE << " meters] "
<< " Discarding " << bytesAvailable << " remaining bytes."; << " Discarding " << bytesAvailable << " remaining bytes.";
}
return bytesAvailable; // assume we read the entire buffer... return bytesAvailable; // assume we read the entire buffer...
} }
@ -322,7 +327,7 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
: sizeof(childInBufferMask); : sizeof(childInBufferMask);
if (bytesLeftToRead < bytesForMasks) { if (bytesLeftToRead < bytesForMasks) {
if (wantDebug) { if (bytesLeftToRead > 0) {
qDebug() << "UNEXPECTED: readElementDataFromBuffer() only had " << bytesLeftToRead << " bytes before masks. " qDebug() << "UNEXPECTED: readElementDataFromBuffer() only had " << bytesLeftToRead << " bytes before masks. "
"Not enough for meaningful data."; "Not enough for meaningful data.";
} }
@ -385,7 +390,6 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long
ReadBitstreamToTreeParams& args) { ReadBitstreamToTreeParams& args) {
int bytesRead = 0; int bytesRead = 0;
const unsigned char* bitstreamAt = bitstream; const unsigned char* bitstreamAt = bitstream;
bool wantDebug = false;
// If destination element is not included, set it to root // If destination element is not included, set it to root
if (!args.destinationElement) { if (!args.destinationElement) {
@ -398,14 +402,24 @@ void Octree::readBitstreamToTree(const unsigned char * bitstream, unsigned long
while (bitstreamAt < bitstream + bufferSizeBytes) { while (bitstreamAt < bitstream + bufferSizeBytes) {
OctreeElement* bitstreamRootElement = nodeForOctalCode(args.destinationElement, (unsigned char *)bitstreamAt, NULL); OctreeElement* bitstreamRootElement = nodeForOctalCode(args.destinationElement, (unsigned char *)bitstreamAt, NULL);
int numberOfThreeBitSectionsInStream = numberOfThreeBitSectionsInCode(bitstreamAt, bufferSizeBytes); int numberOfThreeBitSectionsInStream = numberOfThreeBitSectionsInCode(bitstreamAt, bufferSizeBytes);
if (numberOfThreeBitSectionsInStream > UNREASONABLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"UNEXPECTED: parsing of the octal code would make UNREASONABLY_DEEP_RECURSION... "
"numberOfThreeBitSectionsInStream: \\d+ This buffer is corrupt. Returning."
);
qDebug() << "UNEXPECTED: parsing of the octal code would make UNREASONABLY_DEEP_RECURSION... "
"numberOfThreeBitSectionsInStream:" << numberOfThreeBitSectionsInStream <<
"This buffer is corrupt. Returning.";
return;
}
if (numberOfThreeBitSectionsInStream == OVERFLOWED_OCTCODE_BUFFER) { if (numberOfThreeBitSectionsInStream == OVERFLOWED_OCTCODE_BUFFER) {
if (wantDebug) {
qDebug() << "UNEXPECTED: parsing of the octal code would overflow the buffer. " qDebug() << "UNEXPECTED: parsing of the octal code would overflow the buffer. "
"This buffer is corrupt. Returning."; "This buffer is corrupt. Returning.";
}
return; return;
} }

View file

@ -373,7 +373,7 @@ protected:
static bool countOctreeElementsOperation(OctreeElement* element, void* extraData); static bool countOctreeElementsOperation(OctreeElement* element, void* extraData);
OctreeElement* nodeForOctalCode(OctreeElement* ancestorElement, const unsigned char* needleCode, OctreeElement** parentOfFoundElement) const; OctreeElement* nodeForOctalCode(OctreeElement* ancestorElement, const unsigned char* needleCode, OctreeElement** parentOfFoundElement) const;
OctreeElement* createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach); OctreeElement* createMissingElement(OctreeElement* lastParentElement, const unsigned char* codeToReach, int recursionCount = 0);
int readElementData(OctreeElement *destinationElement, const unsigned char* nodeData, int readElementData(OctreeElement *destinationElement, const unsigned char* nodeData,
int bufferSizeBytes, ReadBitstreamToTreeParams& args); int bufferSizeBytes, ReadBitstreamToTreeParams& args);

View file

@ -35,10 +35,11 @@ const int MAX_TREE_SLICE_BYTES = 26;
const float VIEW_FRUSTUM_FOV_OVERSEND = 60.0f; const float VIEW_FRUSTUM_FOV_OVERSEND = 60.0f;
// These are guards to prevent our voxel tree recursive routines from spinning out of control // These are guards to prevent our voxel tree recursive routines from spinning out of control
const int UNREASONABLY_DEEP_RECURSION = 20; // use this for something that you want to be shallow, but not spin out const int UNREASONABLY_DEEP_RECURSION = 29; // use this for something that you want to be shallow, but not spin out
const int DANGEROUSLY_DEEP_RECURSION = 200; // use this for something that needs to go deeper const int DANGEROUSLY_DEEP_RECURSION = 200; // use this for something that needs to go deeper
const float SCALE_AT_UNREASONABLY_DEEP_RECURSION = (1.0f / powf(2.0f, UNREASONABLY_DEEP_RECURSION)); const float SCALE_AT_UNREASONABLY_DEEP_RECURSION = (1.0f / powf(2.0f, UNREASONABLY_DEEP_RECURSION));
const float SCALE_AT_DANGEROUSLY_DEEP_RECURSION = (1.0f / powf(2.0f, DANGEROUSLY_DEEP_RECURSION)); const float SCALE_AT_DANGEROUSLY_DEEP_RECURSION = (1.0f / powf(2.0f, DANGEROUSLY_DEEP_RECURSION));
const float SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE = SCALE_AT_UNREASONABLY_DEEP_RECURSION * 2.0f; // 0.00006103515 meter ~1/10,0000th
const int DEFAULT_MAX_OCTREE_PPS = 600; // the default maximum PPS we think any octree based server should send to a client const int DEFAULT_MAX_OCTREE_PPS = 600; // the default maximum PPS we think any octree based server should send to a client

View file

@ -16,6 +16,7 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <LogHandler.h>
#include <NodeList.h> #include <NodeList.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <AACubeShape.h> #include <AACubeShape.h>
@ -1159,6 +1160,10 @@ OctreeElement* OctreeElement::addChildAtIndex(int childIndex) {
bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCount) { bool OctreeElement::safeDeepDeleteChildAtIndex(int childIndex, int recursionCount) {
bool deleteApproved = false; bool deleteApproved = false;
if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { if (recursionCount > DANGEROUSLY_DEEP_RECURSION) {
static QString repeatedMessage
= LogHandler::getInstance().addRepeatedMessageRegex(
"OctreeElement::safeDeepDeleteChildAtIndex\\(\\) reached DANGEROUSLY_DEEP_RECURSION, bailing!");
qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!"; qDebug() << "OctreeElement::safeDeepDeleteChildAtIndex() reached DANGEROUSLY_DEEP_RECURSION, bailing!";
return deleteApproved; return deleteApproved;
} }

View file

@ -36,8 +36,6 @@ class ReadBitstreamToTreeParams;
class Shape; class Shape;
class VoxelSystem; class VoxelSystem;
const float SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE = (1.0f / TREE_SCALE) / 10000.0f; // 1/10,000th of a meter
// Callers who want delete hook callbacks should implement this class // Callers who want delete hook callbacks should implement this class
class OctreeElementDeleteHook { class OctreeElementDeleteHook {
public: public:

View file

@ -12,6 +12,7 @@
#include <QColor> #include <QColor>
#include <QUrl> #include <QUrl>
#include <QUuid> #include <QUuid>
#include <QRect>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
@ -30,6 +31,7 @@ void registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue); qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue);
qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue); qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue);
qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue);
qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue);
qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue); qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue);
qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue);
qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue); qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue);
@ -96,6 +98,22 @@ void quatFromScriptValue(const QScriptValue &object, glm::quat& quat) {
quat.w = object.property("w").toVariant().toFloat(); quat.w = object.property("w").toVariant().toFloat();
} }
QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect) {
QScriptValue obj = engine->newObject();
obj.setProperty("x", rect.x());
obj.setProperty("y", rect.y());
obj.setProperty("width", rect.width());
obj.setProperty("height", rect.height());
return obj;
}
void qRectFromScriptValue(const QScriptValue &object, QRect& rect) {
rect.setX(object.property("x").toVariant().toInt());
rect.setY(object.property("y").toVariant().toInt());
rect.setWidth(object.property("width").toVariant().toInt());
rect.setHeight(object.property("height").toVariant().toInt());
}
QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color) { QScriptValue xColorToScriptValue(QScriptEngine *engine, const xColor& color) {
QScriptValue obj = engine->newObject(); QScriptValue obj = engine->newObject();
obj.setProperty("red", color.red); obj.setProperty("red", color.red);

View file

@ -42,6 +42,9 @@ void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2);
QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat& quat); QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat& quat);
void quatFromScriptValue(const QScriptValue &object, glm::quat& quat); void quatFromScriptValue(const QScriptValue &object, glm::quat& quat);
QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect);
void qRectFromScriptValue(const QScriptValue& object, QRect& rect);
QScriptValue xColorToScriptValue(QScriptEngine* engine, const xColor& color); QScriptValue xColorToScriptValue(QScriptEngine* engine, const xColor& color);
void xColorFromScriptValue(const QScriptValue &object, xColor& color); void xColorFromScriptValue(const QScriptValue &object, xColor& color);