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

This commit is contained in:
Atlante45 2015-07-14 12:31:37 -07:00
commit 7bf45308b6
64 changed files with 1176 additions and 808 deletions

View file

@ -11,24 +11,26 @@
//
"use strict";
/*jslint vars: true*/
var Script, Entities, MyAvatar, Window, Overlays, Controller, Vec3, Quat, print, ToolBar; // Referenced globals provided by High Fidelity.
Script.include(["../../libraries/toolBars.js"]);
var Script, Entities, MyAvatar, Window, Overlays, Controller, Vec3, Quat, print, ToolBar, Settings; // Referenced globals provided by High Fidelity.
Script.include("http://s3.amazonaws.com/hifi-public/scripts/libraries/toolBars.js");
var hand = "right";
var hand = Settings.getValue("highfidelity.sword.hand", "right");
var nullActionID = "00000000-0000-0000-0000-000000000000";
var controllerID;
var controllerActive;
var stickID = null;
var actionID = nullActionID;
var targetIDs = [];
var dimensions = { x: 0.3, y: 0.1, z: 2.0 };
var AWAY_ORIENTATION = Quat.fromPitchYawRollDegrees(-90, 0, 0);
var dimensions = { x: 0.3, y: 0.15, z: 2.0 };
var BUTTON_SIZE = 32;
var stickModel = "https://hifi-public.s3.amazonaws.com/eric/models/stick.fbx";
var swordModel = "https://hifi-public.s3.amazonaws.com/ozan/props/sword/sword.fbx";
var swordCollisionShape = "https://hifi-public.s3.amazonaws.com/ozan/props/sword/sword.obj";
var swordCollisionSoundURL = "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/swordStrike1.wav";
var avatarCollisionSoundURL = "https://s3.amazonaws.com/hifi-public/sounds/Collisions-hitsandslaps/airhockey_hit1.wav";
var whichModel = "sword";
var attachmentOffset, MOUSE_CONTROLLER_OFFSET = {x: 0.5, y: 0.4, z: 0.0}; // A fudge when using mouse rather than hand-controller, to hit yourself less often.
var originalAvatarCollisionSound;
var toolBar = new ToolBar(0, 0, ToolBar.vertical, "highfidelity.sword.toolbar", function () {
return {x: 100, y: 380};
@ -37,6 +39,7 @@ var toolBar = new ToolBar(0, 0, ToolBar.vertical, "highfidelity.sword.toolbar",
var SWORD_IMAGE = "http://s3.amazonaws.com/hifi-public/images/billiardsReticle.png"; // Toggle between brandishing/sheathing sword (creating if necessary)
var TARGET_IMAGE = "http://s3.amazonaws.com/hifi-public/images/puck.png"; // Create a target dummy
var CLEANUP_IMAGE = "http://s3.amazonaws.com/hifi-public/images/delete.png"; // Remove sword and all target dummies.f
var SWITCH_HANDS_IMAGE = "http://s3.amazonaws.com/hifi-public/images/up-arrow.svg"; // Toggle left vs right hand. Persists in settings.
var swordButton = toolBar.addOverlay("image", {
width: BUTTON_SIZE,
height: BUTTON_SIZE,
@ -49,6 +52,12 @@ var targetButton = toolBar.addOverlay("image", {
imageURL: TARGET_IMAGE,
alpha: 1
});
var switchHandsButton = toolBar.addOverlay("image", {
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: SWITCH_HANDS_IMAGE,
alpha: 1
});
var cleanupButton = toolBar.addOverlay("image", {
width: BUTTON_SIZE,
height: BUTTON_SIZE,
@ -77,53 +86,51 @@ function flash(color) {
flasher.timer = Script.setTimeout(clearFlash, 500);
}
var health = 100;
var display;
var isAway = false;
var display2d, display3d;
function trackAvatarWithText() {
Entities.editEntity(display3d, {
position: Vec3.sum(MyAvatar.position, {x: 0, y: 1.5, z: 0}),
rotation: Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollDegrees(0, 180, 0))
});
}
function updateDisplay() {
var text = health.toString();
if (!display) {
if (!display2d) {
health = 100;
display = Overlays.addOverlay("text", {
display2d = Overlays.addOverlay("text", {
text: text,
font: { size: 20 },
color: {red: 0, green: 255, blue: 0},
backgroundColor: {red: 100, green: 100, blue: 100}, // Why doesn't this and the next work?
backgroundAlpha: 0.9,
x: Window.innerWidth - 50,
y: 50
x: toolBar.x - 5, // I'd like to add the score to the toolBar and have it drag with it, but toolBar doesn't support text (just buttons).
y: toolBar.y - 30 // So next best thing is to position it each time as if it were on top.
});
display3d = Entities.addEntity({
name: MyAvatar.displayName + " score",
textColor: {red: 255, green: 255, blue: 255},
type: "Text",
text: text,
lineHeight: 0.14,
backgroundColor: {red: 64, green: 64, blue: 64},
dimensions: {x: 0.3, y: 0.2, z: 0.01},
});
Script.update.connect(trackAvatarWithText);
} else {
Overlays.editOverlay(display, {text: text});
Overlays.editOverlay(display2d, {text: text});
Entities.editEntity(display3d, {text: text});
}
}
function removeDisplay() {
if (display) {
Overlays.deleteOverlay(display);
display = null;
if (display2d) {
Overlays.deleteOverlay(display2d);
display2d = null;
Script.update.disconnect(trackAvatarWithText);
Entities.deleteEntity(display3d);
display3d = null;
}
}
function cleanUp(leaveButtons) {
attachmentOffset = {x: 0, y: 0, z: 0};
if (stickID) {
Entities.deleteAction(stickID, actionID);
Entities.deleteEntity(stickID);
stickID = null;
actionID = null;
}
targetIDs.forEach(function (id) {
Entities.deleteAction(id.entity, id.action);
Entities.deleteEntity(id.entity);
});
targetIDs = [];
removeDisplay();
if (!leaveButtons) {
toolBar.cleanup();
}
}
function computeEnergy(collision, entityID) {
var id = entityID || collision.idA || collision.idB;
var entity = id && Entities.getEntityProperties(id);
@ -133,31 +140,69 @@ function computeEnergy(collision, entityID) {
return Math.min(Math.max(1.0, Math.round(energy)), 20);
}
function gotHit(collision) {
if (isAway) { return; }
var energy = computeEnergy(collision);
print("Got hit - " + energy + " from " + collision.idA + " " + collision.idB);
health -= energy;
flash({red: 255, green: 0, blue: 0});
updateDisplay();
}
function scoreHit(idA, idB, collision) {
if (isAway) { return; }
var energy = computeEnergy(collision, idA);
print("Score + " + energy + " from " + JSON.stringify(idA) + " " + JSON.stringify(idB));
health += energy;
flash({red: 0, green: 255, blue: 0});
updateDisplay();
}
function positionStick(stickOrientation) {
var baseOffset = Vec3.sum(attachmentOffset, {x: 0.0, y: 0.0, z: -dimensions.z / 2});
var offset = Vec3.multiplyQbyV(stickOrientation, baseOffset);
Entities.updateAction(stickID, actionID, {relativePosition: offset,
relativeRotation: stickOrientation});
function isFighting() {
return stickID && (actionID !== nullActionID);
}
function initControls() {
print("Sword hand is " + hand);
if (hand === "right") {
controllerID = 3; // right handed
} else {
controllerID = 4; // left handed
}
}
var inHand = false;
function positionStick(stickOrientation) {
var reorient = Quat.fromPitchYawRollDegrees(0, -90, 0);
var baseOffset = {x: -dimensions.z * 0.8, y: 0, z: 0};
var offset = Vec3.multiplyQbyV(reorient, baseOffset);
stickOrientation = Quat.multiply(reorient, stickOrientation);
inHand = false;
Entities.updateAction(stickID, actionID, {
relativePosition: offset,
relativeRotation: stickOrientation,
hand: "right"
});
}
function resetToHand() { // For use with controllers, puts the sword in contact with the hand.
// Maybe coordinate with positionStick?
if (inHand) { // Optimization: bail if we're already inHand.
return;
}
print('Reset to hand');
Entities.updateAction(stickID, actionID, {
relativePosition: {x: 0.0, y: 0.0, z: -dimensions.z * 0.5},
relativeRotation: Quat.fromVec3Degrees({x: 45.0, y: 0.0, z: 0.0}),
hand: hand, // It should not be necessary to repeat these two, but there seems to be a bug in that that
timeScale: 0.05 // they do not retain their earlier values if you don't repeat them.
});
inHand = true;
}
function isControllerActive() {
// I don't think the hydra API provides any reliable way to know whether a particular controller is active. Ask for both.
controllerActive = (Vec3.length(Controller.getSpatialControlPosition(3)) > 0) || Vec3.length(Controller.getSpatialControlPosition(4)) > 0;
return controllerActive;
}
function mouseMoveEvent(event) {
attachmentOffset = MOUSE_CONTROLLER_OFFSET;
if (!stickID || actionID === nullActionID || isAway) {
// When a controller like the hydra gives a mouse event, the x/y is not meaningful to us, but we can detect with a truty deviceID
if (event.deviceID || !isFighting() || isControllerActive()) {
print('Attempting attachment reset');
resetToHand();
return;
}
var windowCenterX = Window.innerWidth / 2;
@ -167,73 +212,88 @@ function mouseMoveEvent(event) {
var mouseXRatio = mouseXCenterOffset / windowCenterX;
var mouseYRatio = mouseYCenterOffset / windowCenterY;
var stickOrientation = Quat.fromPitchYawRollDegrees(mouseYRatio * -90, mouseXRatio * -90, 0);
var stickOrientation = Quat.fromPitchYawRollDegrees(mouseYRatio * 90, mouseXRatio * 90, 0);
positionStick(stickOrientation);
}
function initControls() {
if (hand === "right") {
controllerID = 3; // right handed
} else {
controllerID = 4; // left handed
function removeSword() {
if (stickID) {
print('deleting action ' + actionID + ' and entity ' + stickID);
Entities.deleteAction(stickID, actionID);
Entities.deleteEntity(stickID);
stickID = null;
actionID = nullActionID;
Controller.mouseMoveEvent.disconnect(mouseMoveEvent);
MyAvatar.collisionWithEntity.disconnect(gotHit);
// removeEventhHandler happens automatically when the entity is deleted.
}
inHand = false;
if (originalAvatarCollisionSound !== undefined) {
MyAvatar.collisionSoundURL = originalAvatarCollisionSound;
}
removeDisplay();
}
function cleanUp(leaveButtons) {
removeSword();
targetIDs.forEach(function (id) {
Entities.deleteAction(id.entity, id.action);
Entities.deleteEntity(id.entity);
});
targetIDs = [];
if (!leaveButtons) {
toolBar.cleanup();
}
}
function update() {
var palmPosition = Controller.getSpatialControlPosition(controllerID);
controllerActive = (Vec3.length(palmPosition) > 0);
if (!controllerActive) {
return;
}
var stickOrientation = Controller.getSpatialControlRawRotation(controllerID);
var adjustment = Quat.fromPitchYawRollDegrees(180, 0, 0);
stickOrientation = Quat.multiply(stickOrientation, adjustment);
positionStick(stickOrientation);
}
function toggleAway() {
isAway = !isAway;
if (isAway) {
positionStick(AWAY_ORIENTATION);
removeDisplay();
function makeSword() {
initControls();
var swordPosition;
if (!isControllerActive()) { // Dont' knock yourself with sword
swordPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation)));
} else if (hand === 'right') {
swordPosition = MyAvatar.getRightPalmPosition();
} else {
updateDisplay();
swordPosition = MyAvatar.getLeftPalmPosition();
}
stickID = Entities.addEntity({
type: "Model",
modelURL: swordModel,
compoundShapeURL: swordCollisionShape,
dimensions: dimensions,
position: swordPosition,
rotation: MyAvatar.orientation,
damping: 0.1,
collisionSoundURL: swordCollisionSoundURL,
restitution: 0.01,
collisionsWillMove: true
});
actionID = Entities.addAction("hold", stickID, {
relativePosition: {x: 0.0, y: 0.0, z: -dimensions.z * 0.5},
relativeRotation: Quat.fromVec3Degrees({x: 45.0, y: 0.0, z: 0.0}),
hand: hand,
timeScale: 0.05
});
if (actionID === nullActionID) {
print('*** FAILED TO MAKE SWORD ACTION ***');
cleanUp();
}
if (originalAvatarCollisionSound === undefined) {
originalAvatarCollisionSound = MyAvatar.collisionSoundURL; // We won't get MyAvatar.collisionWithEntity unless there's a sound URL. (Bug.)
SoundCache.getSound(avatarCollisionSoundURL); // Interface does not currently "preload" this? (Bug?)
}
MyAvatar.collisionSoundURL = avatarCollisionSoundURL;
Controller.mouseMoveEvent.connect(mouseMoveEvent);
MyAvatar.collisionWithEntity.connect(gotHit);
Script.addEventHandler(stickID, 'collisionWithEntity', scoreHit);
updateDisplay();
}
function onClick(event) {
switch (Overlays.getOverlayAtPoint(event)) {
case swordButton:
if (!stickID) {
initControls();
stickID = Entities.addEntity({
type: "Model",
modelURL: (whichModel === "sword") ? swordModel : stickModel,
//compoundShapeURL: "https://hifi-public.s3.amazonaws.com/eric/models/stick.obj",
shapeType: "box",
dimensions: dimensions,
position: MyAvatar.getRightPalmPosition(), // initial position doesn't matter, as long as it's close
rotation: MyAvatar.orientation,
damping: 0.1,
collisionSoundURL: "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/swordStrike1.wav",
restitution: 0.01,
collisionsWillMove: true
});
actionID = Entities.addAction("hold", stickID, {relativePosition: {x: 0.0, y: 0.0, z: -dimensions.z / 2},
hand: hand,
timeScale: 0.15});
if (actionID === nullActionID) {
print('*** FAILED TO MAKE SWORD ACTION ***');
cleanUp();
}
Script.addEventHandler(stickID, 'collisionWithEntity', scoreHit);
updateDisplay();
makeSword();
} else {
toggleAway();
removeSword();
}
break;
case targetButton:
@ -256,6 +316,12 @@ function onClick(event) {
});
targetIDs.push({entity: boxId, action: action});
break;
case switchHandsButton:
cleanUp('leaveButtons');
hand = hand === "right" ? "left" : "right";
Settings.setValue("highfidelity.sword.hand", hand);
makeSword();
break;
case cleanupButton:
cleanUp('leaveButtons');
break;
@ -263,7 +329,4 @@ function onClick(event) {
}
Script.scriptEnding.connect(cleanUp);
Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.mousePressEvent.connect(onClick);
Script.update.connect(update);
MyAvatar.collisionWithEntity.connect(gotHit);

View file

@ -43,9 +43,10 @@ var gMaxGrabDistance;
// elevationAzimuth
var gGrabMode = "xzplane";
// gGrabOffset allows the user to grab an object off-center. It points from ray's intersection
// with the move-plane to object center (at the moment the grab is initiated). Future target positions
// are relative to the ray's intersection by the same offset.
// gGrabOffset allows the user to grab an object off-center. It points from the object's center
// to the point where the ray intersects the grab plane (at the moment the grab is initiated).
// Future target positions of the ray intersection are on the same plane, and the offset is subtracted
// to compute the target position of the object's center.
var gGrabOffset = { x: 0, y: 0, z: 0 };
var gTargetPosition;
@ -152,7 +153,6 @@ function computeNewGrabPlane() {
maybeResetMousePosition = true;
}
gGrabMode = "xzPlane";
gPointOnPlane = gCurrentPosition;
gPlaneNormal = { x: 0, y: 1, z: 0 };
if (gLiftKey) {
if (!gRotateKey) {
@ -163,7 +163,7 @@ function computeNewGrabPlane() {
gGrabMode = "rotate";
}
gPointOnPlane = Vec3.subtract(gCurrentPosition, gGrabOffset);
gPointOnPlane = Vec3.sum(gCurrentPosition, gGrabOffset);
var xzOffset = Vec3.subtract(gPointOnPlane, Camera.getPosition());
xzOffset.y = 0;
gXzDistanceToGrab = Vec3.length(xzOffset);
@ -220,8 +220,8 @@ function mousePressEvent(event) {
nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction);
gPointOnPlane = Vec3.sum(cameraPosition, nearestPoint);
// compute the grab offset
gGrabOffset = Vec3.subtract(gStartPosition, gPointOnPlane);
// compute the grab offset (points from object center to point of grab)
gGrabOffset = Vec3.subtract(gPointOnPlane, gStartPosition);
computeNewGrabPlane();
@ -258,6 +258,7 @@ function mouseMoveEvent(event) {
if (Vec3.length(entityProperties.gravity) != 0) {
gOriginalGravity = entityProperties.gravity;
}
gCurrentPosition = entityProperties.position;
var actionArgs = {};
@ -287,6 +288,7 @@ function mouseMoveEvent(event) {
var pointOnCylinder = Vec3.multiply(planeNormal, gXzDistanceToGrab);
pointOnCylinder = Vec3.sum(Camera.getPosition(), pointOnCylinder);
newTargetPosition = mouseIntersectionWithPlane(pointOnCylinder, planeNormal, event);
gPointOnPlane = Vec3.sum(newTargetPosition, gGrabOffset);
} else {
var cameraPosition = Camera.getPosition();
newTargetPosition = mouseIntersectionWithPlane(gPointOnPlane, gPlaneNormal, event);
@ -298,7 +300,7 @@ function mouseMoveEvent(event) {
newTargetPosition = Vec3.sum(relativePosition, cameraPosition);
}
}
gTargetPosition = Vec3.sum(newTargetPosition, gGrabOffset);
gTargetPosition = Vec3.subtract(newTargetPosition, gGrabOffset);
actionArgs = {targetPosition: gTargetPosition, linearTimeScale: 0.1};
}
gPreviousMouse = { x: event.x, y: event.y };

View file

@ -65,70 +65,55 @@ function removeLine() {
function createOrUpdateLine(event) {
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
var props = Entities.getEntityProperties(intersection.entityID);
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
var props = Entities.getEntityProperties(intersection.entityID);
if (intersection.intersects && userCanPoint) {
var points = [nearLinePoint(intersection.intersection), intersection.intersection]
if (lineIsRezzed) {
Entities.editEntity(lineEntityID, {
position: nearLinePoint(intersection.intersection),
linePoints: points,
dimensions: {
x: 1,
y: 1,
z: 1
},
lifetime: 15 + props.lifespan // renew lifetime
});
if (intersection.intersects && userCanPoint) {
var points = [Vec3.subtract(nearLinePoint(intersection.intersection), MyAvatar.position),
Vec3.subtract(intersection.intersection, MyAvatar.position)];
if (lineIsRezzed) {
Entities.editEntity(lineEntityID, {
linePoints: points,
position: MyAvatar.position,
lifetime: 15 + props.lifespan // renew lifetime
});
// Entities.setAllPoints(lineEntityID, points);
} else {
lineIsRezzed = true;
lineEntityID = Entities.addEntity({
type: "Line",
position: MyAvatar.position,
linePoints: points,
dimensions: { x: 100, y: 100, z: 100 },
color: { red: 255, green: 255, blue: 255 },
lifetime: 15 // if someone crashes while pointing, don't leave the line there forever.
});
}
} else {
lineIsRezzed = true;
lineEntityID = Entities.addEntity({
type: "Line",
position: nearLinePoint(intersection.intersection),
linePoints: points,
dimensions: {
x: 1,
y: 1,
z: 1
},
color: {
red: 255,
green: 255,
blue: 255
},
lifetime: 15 // if someone crashes while pointing, don't leave the line there forever.
});
removeLine();
}
} else {
removeLine();
}
}
function mousePressEvent(event) {
if (!event.isLeftButton) {
return;
}
createOrUpdateLine(event);
var clickedOverlay = Overlays.getOverlayAtPoint({
x: event.x,
y: event.y
});
if (clickedOverlay == pointerButton) {
userCanPoint = !userCanPoint;
if (userCanPoint === true) {
Overlays.editOverlay(pointerButton, {
color: buttonOnColor
});
} else {
Overlays.editOverlay(pointerButton, {
color: buttonOffColor
});
if (!event.isLeftButton) {
return;
}
var clickedOverlay = Overlays.getOverlayAtPoint({
x: event.x,
y: event.y
});
if (clickedOverlay == pointerButton) {
userCanPoint = !userCanPoint;
if (userCanPoint === true) {
Overlays.editOverlay(pointerButton, { color: buttonOnColor });
} else {
Overlays.editOverlay(pointerButton, { color: buttonOffColor });
}
}
}
}

View file

@ -2,6 +2,32 @@ var controlHeld = false;
var shiftHeld = false;
function attemptVoxelChange(intersection) {
var ids = Entities.findEntities(intersection.intersection, 10);
var success = false;
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
if (controlHeld) {
// hold control to erase a sphere
if (Entities.setVoxelSphere(id, intersection.intersection, 1.0, 0)) {
success = true;
}
} else if (shiftHeld) {
// hold shift to set all voxels to 255
if (Entities.setAllVoxels(id, 255)) {
success = true;
}
} else {
// no modifier key means to add a sphere
if (Entities.setVoxelSphere(id, intersection.intersection, 1.0, 255)) {
success = true;
}
}
}
return success;
}
function mousePressEvent(event) {
if (!event.isLeftButton) {
return;
@ -9,20 +35,21 @@ function mousePressEvent(event) {
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
// var props = Entities.getEntityProperties(intersection.entityID);
// we've used a picking ray to decide where to add the new sphere of voxels. If we pick nothing
// or if we pick a non-PolyVox entity, we fall through to the next picking attempt.
if (intersection.intersects) {
var ids = Entities.findEntities(intersection.intersection, 10);
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
if (controlHeld) {
Entities.setVoxelSphere(id, intersection.intersection, 1.0, 0);
} else if (shiftHeld) {
Entities.setAllVoxels(id, 255);
} else {
Entities.setVoxelSphere(id, intersection.intersection, 1.0, 255);
}
if (attemptVoxelChange(intersection)) {
return;
}
}
// if the PolyVox entity is empty, we can't pick against its voxel. try picking against its
// bounding box, instead.
intersection = Entities.findRayIntersection(pickRay, false); // bounding box picking
if (intersection.intersects) {
attemptVoxelChange(intersection);
}
}

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 261 261" enable-background="new 0 0 261 261" xml:space="preserve">
<g>
<g>
<circle fill="#149ABB" cx="130.5" cy="130.5" r="130.5"/>
</g>
<g>
<path fill="#0C9AB2" d="M251,80.6c27.5,66.6-4.3,142.9-70.9,170.4S37.1,246.7,9.6,180"/>
</g>
<g opacity="0.21">
<g>
<path fill="#FFFFFF" d="M130.5,1.8c17.4,0,34.2,3.4,50.1,10.1c15.3,6.5,29.1,15.8,40.9,27.6s21.1,25.6,27.6,40.9
c6.7,15.9,10.1,32.7,10.1,50.1s-3.4,34.2-10.1,50.1c-6.5,15.3-15.8,29.1-27.6,40.9c-11.8,11.8-25.6,21.1-40.9,27.6
c-15.9,6.7-32.7,10.1-50.1,10.1s-34.2-3.4-50.1-10.1c-15.3-6.5-29.1-15.8-40.9-27.6c-11.8-11.8-21.1-25.6-27.6-40.9
c-6.7-15.9-10.1-32.7-10.1-50.1s3.4-34.2,10.1-50.1c6.5-15.3,15.8-29.1,27.6-40.9s25.6-21.1,40.9-27.6
C96.3,5.2,113.1,1.8,130.5,1.8 M130.5,0C58.4,0,0,58.4,0,130.5S58.4,261,130.5,261S261,202.6,261,130.5S202.6,0,130.5,0L130.5,0z
"/>
</g>
</g>
<rect x="100.8" y="65.2" fill="#FFFFFF" width="59.4" height="98"/>
<rect x="3.4" y="169.4" fill="#FFFFFF" width="254.2" height="1.9"/>
<rect x="3.4" y="176" fill="#FFFFFF" width="254.2" height="1.9"/>
<rect x="3.4" y="184.7" fill="#FFFFFF" width="254.2" height="1.9"/>
<rect x="3.4" y="197.9" fill="#FFFFFF" width="254.2" height="1.9"/>
<path fill="#FFFFFF" d="M93.7,169.5l-14.7,75.8c0,0,47.4,23.4,101.2,0.5c33.3-14.2,51.5-41.5,51.5-41.5L154,170.2L93.7,169.5z"/>
<path fill="#FFFFFF" d="M166,169.5l14.7,75.8c0,0-47.4,23.4-101.2,0.5c-33.3-14.2-51.5-41.5-51.5-41.5l77.5-34.1L166,169.5z"/>
<rect x="85.8" y="184.7" fill="#149ABB" width="89.4" height="1.9"/>
<rect x="98" y="176" fill="#149ABB" width="65.1" height="1.9"/>
<rect x="56.4" y="197.9" fill="#149ABB" width="148.2" height="1.9"/>
<rect x="51.4" y="219.4" fill="#149ABB" width="158.3" height="1.9"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -41,8 +41,6 @@ DialogContainer {
readonly property int closeMargin: 16
readonly property real tan30: 0.577 // tan(30°)
readonly property int inputSpacing: 16
property int maximumX: parent ? parent.width - width : 0
property int maximumY: parent ? parent.height - height : 0
Rectangle {
id: backgroundRectangle

View file

@ -1,164 +1,176 @@
import Hifi 1.0
import QtQuick 2.3
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
import QtGraphicalEffects 1.0
import "controls"
import "styles"
DialogContainer {
HifiConstants { id: hifi }
id: root
HifiConstants { id: hifi }
objectName: "UpdateDialog"
implicitWidth: updateDialog.width
implicitHeight: updateDialog.height
implicitWidth: updateDialog.implicitWidth
implicitHeight: updateDialog.implicitHeight
x: parent ? parent.width / 2 - width / 2 : 0
y: parent ? parent.height / 2 - height / 2 : 0
property int maximumX: parent ? parent.width - width : 0
property int maximumY: parent ? parent.height - height : 0
UpdateDialog {
id: updateDialog
implicitWidth: backgroundRectangle.width
implicitHeight: backgroundRectangle.height
readonly property int inputWidth: 500
readonly property int inputHeight: 60
readonly property int contentWidth: 500
readonly property int logoSize: 60
readonly property int borderWidth: 30
readonly property int closeMargin: 16
readonly property int inputSpacing: 16
readonly property int buttonWidth: 150
readonly property int buttonHeight: 50
readonly property int buttonRadius: 15
readonly property int buttonWidth: 100
readonly property int buttonHeight: 30
readonly property int noticeHeight: 15 * inputSpacing
readonly property string fontFamily: Qt.platform.os === "windows" ? "Trebuchet MS" : "Trebuchet"
signal triggerBuildDownload
signal closeUpdateDialog
Rectangle {
id: backgroundRectangle
color: "#ffffff"
width: updateDialog.contentWidth + updateDialog.borderWidth * 2
height: mainContent.height + updateDialog.borderWidth * 2 - updateDialog.closeMargin / 2
MouseArea {
width: parent.width
height: parent.height
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
drag {
target: root
minimumX: 0
minimumY: 0
maximumX: root.parent ? root.maximumX : 0
maximumY: root.parent ? root.maximumY : 0
}
}
}
Image {
id: logo
source: "../images/interface-logo.svg"
width: updateDialog.logoSize
height: updateDialog.logoSize
anchors {
top: mainContent.top
right: mainContent.right
}
}
Column {
id: mainContent
width: updateDialog.inputWidth
width: updateDialog.contentWidth
spacing: updateDialog.inputSpacing
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
topMargin: updateDialog.borderWidth
top: parent.top
}
Rectangle {
id: backgroundRectangle
color: "#2c86b1"
opacity: 0.85
radius: updateDialog.closeMargin * 2
width: updateDialog.inputWidth + updateDialog.borderWidth * 2
height: updateDialog.inputHeight * 6 + updateDialog.closeMargin * 2
Rectangle {
id: dialogTitle
width: updateDialog.inputWidth
height: updateDialog.inputHeight
radius: height / 2
color: "#ebebeb"
id: header
width: parent.width - updateDialog.logoSize - updateDialog.inputSpacing
height: updateAvailable.height + versionDetails.height
Text {
id: updateAvailable
text: "Update Available"
font {
family: updateDialog.fontFamily
pixelSize: hifi.fonts.pixelSize * 1.5
weight: Font.DemiBold
}
color: "#303030"
}
Text {
id: versionDetails
text: updateDialog.updateAvailableDetails
font {
family: updateDialog.fontFamily
pixelSize: hifi.fonts.pixelSize * 0.6
letterSpacing: -0.5
}
color: hifi.colors.text
anchors {
top: parent.top
topMargin: updateDialog.inputSpacing
horizontalCenter: parent.horizontalCenter
}
Text {
id: updateAvailableText
text: "Update Available"
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
leftMargin: updateDialog.inputSpacing
}
}
Text {
text: updateDialog.updateAvailableDetails
font.pixelSize: 14
color: hifi.colors.text
anchors {
verticalCenter: parent.verticalCenter
left: updateAvailableText.right
leftMargin: 13
}
top: updateAvailable.bottom
}
}
Flickable {
}
Rectangle {
width: parent.width
height: updateDialog.noticeHeight
border {
width: 1
color: "#a0a0a0"
}
ScrollView {
id: scrollArea
anchors {
top: dialogTitle.bottom
}
contentWidth: updateDialog.inputWidth
contentHeight: backgroundRectangle.height - (dialogTitle.height * 2.5)
width: updateDialog.inputWidth
height: backgroundRectangle.height - (dialogTitle.height * 2.5)
flickableDirection: Flickable.VerticalFlick
clip: true
TextEdit {
id: releaseNotes
wrapMode: TextEdit.Wrap
width: parent.width
readOnly: true
text: updateDialog.releaseNotes
font.pixelSize: 14
color: hifi.colors.text
anchors {
left: parent.left
leftMargin: updateDialog.borderWidth
}
}
}
Rectangle {
id: downloadButton
width: updateDialog.buttonWidth
height: updateDialog.buttonHeight
radius: updateDialog.buttonRadius
color: "green"
anchors {
top: scrollArea.bottom
topMargin: 10
right: backgroundRectangle.right
rightMargin: 15
}
width: parent.width - updateDialog.closeMargin
height: parent.height
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
anchors.right: parent.right
Text {
text: "Upgrade"
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
id: releaseNotes
wrapMode: Text.Wrap
width: parent.width - updateDialog.closeMargin
text: updateDialog.releaseNotes
color: hifi.colors.text
font {
family: updateDialog.fontFamily
pixelSize: hifi.fonts.pixelSize * 0.65
}
}
MouseArea {
id: downloadButtonAction
anchors.fill: parent
onClicked: updateDialog.triggerUpgrade()
cursorShape: "PointingHandCursor"
}
}
}
Row {
anchors.right: parent.right
spacing: updateDialog.inputSpacing
height: updateDialog.buttonHeight + updateDialog.closeMargin / 2
Rectangle {
id: cancelButton
width: updateDialog.buttonWidth
height: updateDialog.buttonHeight
radius: updateDialog.buttonRadius
color: "red"
anchors {
top: scrollArea.bottom
topMargin: 10
right: downloadButton.left
rightMargin: 15
}
anchors.bottom: parent.bottom
Text {
text: "Cancel"
color: "#0c9ab4" // Same as logo
font {
family: updateDialog.fontFamily
pixelSize: hifi.fonts.pixelSize * 1.2
weight: Font.DemiBold
}
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
}
MouseArea {
id: cancelButtonAction
anchors.fill: parent
@ -166,7 +178,35 @@ DialogContainer {
cursorShape: "PointingHandCursor"
}
}
Rectangle {
id: updateButton
width: updateDialog.buttonWidth
height: updateDialog.buttonHeight
anchors.bottom: parent.bottom
Text {
text: "Update"
color: "#0c9ab4" // Same as logo
font {
family: updateDialog.fontFamily
pixelSize: hifi.fonts.pixelSize * 1.2
weight: Font.DemiBold
}
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
}
MouseArea {
id: updateButtonAction
anchors.fill: parent
onClicked: updateDialog.triggerUpgrade()
cursorShape: "PointingHandCursor"
}
}
}
}
}
}
}

View file

@ -3589,23 +3589,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
if (!selfAvatarOnly) {
_nodeBoundsDisplay.draw();
// render octree fades if they exist
if (_octreeFades.size() > 0) {
PerformanceTimer perfTimer("octreeFades");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... octree fades...");
_octreeFadesLock.lockForWrite();
for(std::vector<OctreeFade>::iterator fade = _octreeFades.begin(); fade != _octreeFades.end();) {
fade->render(renderArgs);
if(fade->isDone()) {
fade = _octreeFades.erase(fade);
} else {
++fade;
}
}
_octreeFadesLock.unlock();
}
// give external parties a change to hook in
{
PerformanceTimer perfTimer("inWorldInterface");
@ -3897,17 +3880,6 @@ void Application::nodeKilled(SharedNodePointer node) {
qCDebug(interfaceapp, "model server going away...... v[%f, %f, %f, %f]",
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
// Add the jurisditionDetails object to the list of "fade outs"
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
OctreeFade fade(OctreeFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE);
fade.voxelDetails = rootDetails;
const float slightly_smaller = 0.99f;
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
_octreeFadesLock.lockForWrite();
_octreeFades.push_back(fade);
_octreeFadesLock.unlock();
}
// If the model server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server
_entityServerJurisdictions.lockForWrite();
_entityServerJurisdictions.erase(_entityServerJurisdictions.find(nodeUUID));
@ -3984,16 +3956,6 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin
qPrintable(serverType),
(double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s);
// Add the jurisditionDetails object to the list of "fade outs"
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnOctreeServerChanges)) {
OctreeFade fade(OctreeFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE);
fade.voxelDetails = rootDetails;
const float slightly_smaller = 0.99f;
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
_octreeFadesLock.lockForWrite();
_octreeFades.push_back(fade);
_octreeFadesLock.unlock();
}
} else {
jurisdiction->unlock();
}

View file

@ -72,7 +72,6 @@
#include "ui/ToolWindow.h"
#include "ui/UserInputMapper.h"
#include "devices/KeyboardMouseDevice.h"
#include "octree/OctreeFade.h"
#include "octree/OctreePacketProcessor.h"
#include "UndoStackScriptingInterface.h"
@ -91,16 +90,6 @@ class Node;
class ProgramObject;
class ScriptEngine;
static int RESTART_CODE = 1000;
static const float NODE_ADDED_RED = 0.0f;
static const float NODE_ADDED_GREEN = 1.0f;
static const float NODE_ADDED_BLUE = 0.0f;
static const float NODE_KILLED_RED = 1.0f;
static const float NODE_KILLED_GREEN = 0.0f;
static const float NODE_KILLED_BLUE = 0.0f;
static const QString SNAPSHOT_EXTENSION = ".jpg";
static const QString SVO_EXTENSION = ".svo";
static const QString SVO_JSON_EXTENSION = ".svo.json";
@ -634,8 +623,6 @@ private:
NodeBounds _nodeBoundsDisplay;
std::vector<OctreeFade> _octreeFades;
QReadWriteLock _octreeFadesLock;
ControllerScriptingInterface _controllerScriptingInterface;
QPointer<LogDialog> _logDialog;
QPointer<SnapshotShareDialog> _snapshotShareDialog;

View file

@ -342,7 +342,6 @@ Menu::Menu() {
0, // QML Qt::SHIFT | Qt::Key_A,
true);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
MenuWrapper* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight);
QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu);
@ -460,6 +459,7 @@ Menu::Menu() {
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes);
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false);
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false);
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowWhosLookingAtMe, 0, false);
MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, false);

View file

@ -179,7 +179,6 @@ namespace MenuOption {
const QString DisplayModelElementProxy = "Display Model Element Bounds";
const QString DisplayDebugTimingDetails = "Display Timing Details";
const QString DontDoPrecisionPicking = "Don't Do Precision Picking";
const QString DontFadeOnOctreeServerChanges = "Don't Fade In/Out on Octree Server Changes";
const QString DontRenderEntitiesAsScene = "Don't Render Entities as Scene";
const QString EchoLocalAudio = "Echo Local Audio";
const QString EchoServerAudio = "Echo Server Audio";
@ -271,6 +270,7 @@ namespace MenuOption {
const QString ShowBordersEntityNodes = "Show Entity Nodes";
const QString ShowIKConstraints = "Show IK Constraints";
const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats";
const QString ShowWhosLookingAtMe = "Show Who's Looking at Me";
const QString SimpleShadows = "Simple";
const QString SixenseEnabled = "Enable Hydra Support";
const QString SixenseMouseInput = "Enable Sixense Mouse Input";

View file

@ -130,7 +130,7 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) {
auto geometryCache = DependencyManager::get<GeometryCache>();
geometryCache->useSimpleDrawPipeline(batch);
auto textureCache = DependencyManager::get<TextureCache>();
batch.setUniformTexture(0, textureCache->getWhiteTexture());
batch.setResourceTexture(0, textureCache->getWhiteTexture());
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);
batch.setProjectionTransform(legacyProjection);
batch.setModelTransform(Transform());

View file

@ -453,22 +453,36 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, boo
}
}
// Stack indicator spheres
float indicatorOffset = 0.0f;
if (!_displayName.isEmpty() && _displayNameAlpha != 0.0f) {
const float DISPLAY_NAME_INDICATOR_OFFSET = 0.22f;
indicatorOffset = DISPLAY_NAME_INDICATOR_OFFSET;
}
const float INDICATOR_RADIUS = 0.03f;
const float INDICATOR_INDICATOR_OFFSET = 3.0f * INDICATOR_RADIUS;
// If this is the avatar being looked at, render a little ball above their head
if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) {
const float LOOK_AT_INDICATOR_RADIUS = 0.03f;
const float LOOK_AT_INDICATOR_OFFSET = 0.22f;
const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f };
glm::vec3 position;
if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) {
position = glm::vec3(_position.x, getDisplayNamePosition().y, _position.z);
} else {
position = glm::vec3(_position.x, getDisplayNamePosition().y + LOOK_AT_INDICATOR_OFFSET, _position.z);
}
glm::vec3 position = glm::vec3(_position.x, getDisplayNamePosition().y + indicatorOffset, _position.z);
Transform transform;
transform.setTranslation(position);
batch.setModelTransform(transform);
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, LOOK_AT_INDICATOR_RADIUS
, 15, 15, LOOK_AT_INDICATOR_COLOR);
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, INDICATOR_RADIUS,
15, 15, LOOK_AT_INDICATOR_COLOR);
indicatorOffset += INDICATOR_INDICATOR_OFFSET;
}
// If the avatar is looking at me, render an indication that they area
if (getHead()->getIsLookingAtMe() && Menu::getInstance()->isOptionChecked(MenuOption::ShowWhosLookingAtMe)) {
const glm::vec4 LOOKING_AT_ME_COLOR = { 0.8f, 0.65f, 0.0f, 0.1f };
glm::vec3 position = glm::vec3(_position.x, getDisplayNamePosition().y + indicatorOffset, _position.z);
Transform transform;
transform.setTranslation(position);
batch.setModelTransform(transform);
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, INDICATOR_RADIUS,
15, 15, LOOKING_AT_ME_COLOR);
}
// quick check before falling into the code below:
@ -644,7 +658,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) {
glm::vec2 texCoordBottomRight(1.0f, 1.0f);
gpu::Batch& batch = *renderArgs->_batch;
batch.setUniformTexture(0, _billboardTexture->getGPUTexture());
batch.setResourceTexture(0, _billboardTexture->getGPUTexture());
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, true);
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));

View file

@ -70,30 +70,14 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
return;
}
// check for NaNs
if (position.x != position.x ||
position.y != position.y ||
position.z != position.z) {
qDebug() << "AvatarActionHold::updateActionWorker -- target position includes NaN";
return;
}
if (rotation.x != rotation.x ||
rotation.y != rotation.y ||
rotation.z != rotation.z ||
rotation.w != rotation.w) {
qDebug() << "AvatarActionHold::updateActionWorker -- target rotation includes NaN";
return;
}
if (_positionalTarget != position || _rotationalTarget != rotation) {
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setActionDataDirty(true);
}
_positionalTarget = position;
_rotationalTarget = rotation;
}
_positionalTarget = position;
_rotationalTarget = rotation;
unlock();
ObjectActionSpring::updateActionWorker(deltaTimeStep);
@ -101,59 +85,51 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
bool rPOk = true;
bool ok = true;
glm::vec3 relativePosition =
EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", rPOk, false);
bool rROk = true;
EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false);
if (!ok) {
relativePosition = _relativePosition;
}
ok = true;
glm::quat relativeRotation =
EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", rROk, false);
bool tSOk = true;
EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false);
if (!ok) {
relativeRotation = _relativeRotation;
}
ok = true;
float timeScale =
EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", tSOk, false);
bool hOk = true;
EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", ok, false);
if (!ok) {
timeScale = _linearTimeScale;
}
ok = true;
QString hand =
EntityActionInterface::extractStringArgument("hold", arguments, "hand", hOk, false);
EntityActionInterface::extractStringArgument("hold", arguments, "hand", ok, false);
if (!ok || !(hand == "left" || hand == "right")) {
hand = _hand;
}
lockForWrite();
if (rPOk) {
if (relativePosition != _relativePosition
|| relativeRotation != _relativeRotation
|| timeScale != _linearTimeScale
|| hand != _hand) {
lockForWrite();
_relativePosition = relativePosition;
} else {
_relativePosition = glm::vec3(0.0f, 0.0f, 1.0f);
}
if (rROk) {
_relativeRotation = relativeRotation;
} else {
_relativeRotation = glm::quat(0.0f, 0.0f, 0.0f, 1.0f);
}
const float MIN_TIMESCALE = 0.1f;
_linearTimeScale = glm::min(MIN_TIMESCALE, timeScale);
_angularTimeScale = _linearTimeScale;
_hand = hand;
if (tSOk) {
_linearTimeScale = timeScale;
_angularTimeScale = timeScale;
} else {
_linearTimeScale = 0.2f;
_angularTimeScale = 0.2f;
_mine = true;
_active = true;
activateBody();
unlock();
}
if (hOk) {
hand = hand.toLower();
if (hand == "left") {
_hand = "left";
} else if (hand == "right") {
_hand = "right";
} else {
qDebug() << "hold action -- invalid hand argument:" << hand;
_hand = "right";
}
} else {
_hand = "right";
}
_mine = true;
_positionalTargetSet = true;
_rotationalTargetSet = true;
_active = true;
unlock();
return true;
}

View file

@ -72,9 +72,13 @@ void AvatarManager::init() {
_myAvatar->init();
_avatarHash.insert(MY_AVATAR_KEY, _myAvatar);
connect(DependencyManager::get<SceneScriptingInterface>().data(), &SceneScriptingInterface::shouldRenderAvatarsChanged, this, &AvatarManager::updateAvatarRenderStatus, Qt::QueuedConnection);
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
render::PendingChanges pendingChanges;
_myAvatar->addToScene(_myAvatar, scene, pendingChanges);
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
_myAvatar->addToScene(_myAvatar, scene, pendingChanges);
}
scene->enqueuePendingChanges(pendingChanges);
}
@ -158,7 +162,9 @@ AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWe
auto avatar = std::dynamic_pointer_cast<Avatar>(AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer));
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
render::PendingChanges pendingChanges;
avatar->addToScene(avatar, scene, pendingChanges);
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
avatar->addToScene(avatar, scene, pendingChanges);
}
scene->enqueuePendingChanges(pendingChanges);
return avatar;
}
@ -310,3 +316,23 @@ void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) {
}
}
}
void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) {
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
for (auto avatarData : _avatarHash) {
auto avatar = std::dynamic_pointer_cast<Avatar>(avatarData);
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
render::PendingChanges pendingChanges;
avatar->addToScene(avatar, scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
}
} else {
for (auto avatarData : _avatarHash) {
auto avatar = std::dynamic_pointer_cast<Avatar>(avatarData);
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
render::PendingChanges pendingChanges;
avatar->removeFromScene(avatar, scene, pendingChanges);
scene->enqueuePendingChanges(pendingChanges);
}
}
}

View file

@ -63,6 +63,7 @@ public:
public slots:
void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; }
void updateAvatarRenderStatus(bool shouldRenderAvatars);
private:
AvatarManager(QObject* parent = 0);

View file

@ -117,14 +117,5 @@ int main(int argc, const char* argv[]) {
#endif
qCDebug(interfaceapp, "Normal exit.");
if (exitCode == RESTART_CODE) {
qCDebug(interfaceapp, "Interface restarting.");
QStringList arguments;
for (int i = 0; i < argc; ++i) {
arguments << argv[i];
}
QProcess::startDetached(arguments[0], arguments);
}
return exitCode;
}

View file

@ -1,68 +0,0 @@
//
// OctreeFade.cpp
// interface/src/octree
//
// Created by Brad Hefta-Gaub on 8/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "InterfaceConfig.h"
#include <GlowEffect.h>
#include <GeometryCache.h>
#include <OctreeConstants.h>
#include "Application.h"
#include "OctreeFade.h"
const float OctreeFade::FADE_OUT_START = 0.5f;
const float OctreeFade::FADE_OUT_END = 0.05f;
const float OctreeFade::FADE_OUT_STEP = 0.9f;
const float OctreeFade::FADE_IN_START = 0.05f;
const float OctreeFade::FADE_IN_END = 0.5f;
const float OctreeFade::FADE_IN_STEP = 1.1f;
const float OctreeFade::DEFAULT_RED = 0.5f;
const float OctreeFade::DEFAULT_GREEN = 0.5f;
const float OctreeFade::DEFAULT_BLUE = 0.5f;
OctreeFade::OctreeFade(FadeDirection direction, float red, float green, float blue) :
direction(direction),
red(red),
green(green),
blue(blue)
{
opacity = (direction == FADE_OUT) ? FADE_OUT_START : FADE_IN_START;
}
void OctreeFade::render(RenderArgs* renderArgs) {
DependencyManager::get<GlowEffect>()->begin(renderArgs);
glDisable(GL_LIGHTING);
glPushMatrix();
glScalef(1.0f, 1.0f, 1.0f);
glTranslatef(voxelDetails.x + voxelDetails.s * 0.5f,
voxelDetails.y + voxelDetails.s * 0.5f,
voxelDetails.z + voxelDetails.s * 0.5f);
glLineWidth(1.0f);
DependencyManager::get<GeometryCache>()->renderSolidCube(voxelDetails.s, glm::vec4(red, green, blue, opacity));
glLineWidth(1.0f);
glPopMatrix();
glEnable(GL_LIGHTING);
DependencyManager::get<GlowEffect>()->end(renderArgs);
opacity *= (direction == FADE_OUT) ? FADE_OUT_STEP : FADE_IN_STEP;
}
bool OctreeFade::isDone() const {
if (direction == FADE_OUT) {
return opacity <= FADE_OUT_END;
} else {
return opacity >= FADE_IN_END;
}
return true; // unexpected case, assume we're done
}

View file

@ -1,46 +0,0 @@
//
// OctreeFade.h
// interface/src/octree
//
// Created by Brad Hefta-Gaub on 8/6/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_OctreeFade_h
#define hifi_OctreeFade_h
#include <OctalCode.h> // for VoxelPositionSize
class OctreeFade {
public:
enum FadeDirection { FADE_OUT, FADE_IN};
static const float FADE_OUT_START;
static const float FADE_OUT_END;
static const float FADE_OUT_STEP;
static const float FADE_IN_START;
static const float FADE_IN_END;
static const float FADE_IN_STEP;
static const float DEFAULT_RED;
static const float DEFAULT_GREEN;
static const float DEFAULT_BLUE;
VoxelPositionSize voxelDetails;
FadeDirection direction;
float opacity;
float red;
float green;
float blue;
OctreeFade(FadeDirection direction = FADE_OUT, float red = DEFAULT_RED,
float green = DEFAULT_GREEN, float blue = DEFAULT_BLUE);
void render(RenderArgs* renderArgs);
bool isDone() const;
};
#endif // hifi_OctreeFade_h

View file

@ -179,7 +179,7 @@ void ApplicationCompositor::bindCursorTexture(gpu::Batch& batch, uint8_t cursorI
_cursors[iconId] = DependencyManager::get<TextureCache>()->
getImageTexture(iconPath);
}
batch.setUniformTexture(0, _cursors[iconId]);
batch.setResourceTexture(0, _cursors[iconId]);
}
// Draws the FBO texture for the screen

View file

@ -127,6 +127,7 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) {
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUseProgram(0);
// give external parties a change to hook in
emit qApp->renderingOverlay();
@ -200,7 +201,7 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderAr
geometryCache->useSimpleDrawPipeline(batch);
batch.setProjectionTransform(mat4());
batch.setModelTransform(mat4());
batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
batch._glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH);
// TODO animate the disconnect border for some excitement while not connected?

View file

@ -24,9 +24,18 @@ UpdateDialog::UpdateDialog(QQuickItem* parent) :
int currentVersion = QCoreApplication::applicationVersion().toInt();
int latestVersion = applicationUpdater.data()->getBuildData().lastKey();
int versionsBehind = latestVersion - currentVersion;
_updateAvailableDetails = "v" + QString::number(latestVersion) + " released on " + applicationUpdater.data()->getBuildData()[latestVersion]["releaseTime"];
_updateAvailableDetails += "\nYou are " + QString::number(versionsBehind) + " versions behind";
_releaseNotes = applicationUpdater.data()->getBuildData()[latestVersion]["releaseNotes"];
_updateAvailableDetails = "v" + QString::number(latestVersion) + " released on "
+ QString(applicationUpdater.data()->getBuildData()[latestVersion]["releaseTime"]).replace(" ", " ");
_updateAvailableDetails += "\nYou are " + QString::number(versionsBehind) + " version"
+ (versionsBehind > 1 ? "s" : "") + " behind";
_releaseNotes = "";
for (int i = latestVersion; i > currentVersion; i--) {
QString releaseNotes = applicationUpdater.data()->getBuildData()[i]["releaseNotes"];
releaseNotes.remove("<br />");
releaseNotes.remove(QRegExp("^\n+"));
_releaseNotes += "\n" + QString().sprintf("%d", i) + "\n" + releaseNotes + "\n";
}
}
const QString& UpdateDialog::updateAvailableDetails() const {

View file

@ -87,12 +87,12 @@ void BillboardOverlay::render(RenderArgs* args) {
transform.postScale(glm::vec3(getDimensions(), 1.0f));
batch->setModelTransform(transform);
batch->setUniformTexture(0, _texture->getGPUTexture());
batch->setResourceTexture(0, _texture->getGPUTexture());
DependencyManager::get<GeometryCache>()->renderQuad(*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha));
batch->setUniformTexture(0, args->_whiteTexture); // restore default white color after me
batch->setResourceTexture(0, args->_whiteTexture); // restore default white color after me
}
}

View file

@ -14,6 +14,11 @@
#include <GeometryCache.h>
#include <RegisteredMetaTypes.h>
#include "qapplication.h"
#include "gpu/Context.h"
#include "gpu/StandardShaderLib.h"
ImageOverlay::ImageOverlay() :
_imageURL(),
_renderImage(false),
@ -57,15 +62,42 @@ void ImageOverlay::render(RenderArgs* args) {
return;
}
// TODO: I commented all the code needed to migrate this ImageOverlay rendering from naked gl to gpu::Batch
/*gpu::Batch localBatch;
gpu::Batch& batch = (args->_batch ? (*args->_batch) : localBatch);
static gpu::PipelinePointer drawPipeline;
static int texcoordRectLoc = -1;
static int colorLoc = -1;
if (!drawPipeline) {
auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS, gpu::StandardShaderLib::getDrawColoredTexturePS);
gpu::Shader::makeProgram(*blitProgram);
texcoordRectLoc = blitProgram->getUniforms().findLocation("texcoordRect");
colorLoc = blitProgram->getUniforms().findLocation("color");
gpu::StatePointer blitState = gpu::StatePointer(new gpu::State());
blitState->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
blitState->setColorWriteMask(true, true, true, true);
drawPipeline = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState));
}
*/
// TODO: batch.setPipeline(drawPipeline);
glUseProgram(0);
if (_renderImage) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, _texture->getID());
}
// TODO: batch.setResourceTexture(0, _texture->getGPUTexture());
} // TODO: else {
// TODO: batch.setResourceTexture(0, args->_whiteTexture);
// TODO: }
// TODO: batch.setViewTransform(Transform());
const float MAX_COLOR = 255.0f;
xColor color = getColor();
float alpha = getAlpha();
glm::vec4 quadColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
// TODO: batch._glUniform4fv(colorLoc, 1, (const float*) &quadColor);
int left = _bounds.left();
int right = _bounds.right() + 1;
@ -75,6 +107,12 @@ void ImageOverlay::render(RenderArgs* args) {
glm::vec2 topLeft(left, top);
glm::vec2 bottomRight(right, bottom);
// TODO: Transform model;
// TODO: model.setTranslation(glm::vec3(0.5f * (right + left), 0.5f * (top + bottom), 0.0f));
// TODO: model.setScale(glm::vec3(0.5f * (right - left), 0.5f * (bottom - top), 1.0f));
// TODO: batch.setModelTransform(model);
// if for some reason our image is not over 0 width or height, don't attempt to render the image
if (_renderImage) {
float imageWidth = _texture->getWidth();
@ -104,15 +142,24 @@ void ImageOverlay::render(RenderArgs* args) {
glm::vec2 texCoordTopLeft(x, y);
glm::vec2 texCoordBottomRight(x + w, y + h);
glm::vec4 texcoordRect(texCoordTopLeft, w, h);
// TODO: batch._glUniform4fv(texcoordRectLoc, 1, (const float*) &texcoordRect);
// TODO: batch.draw(gpu::TRIANGLE_STRIP, 4);
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, quadColor);
} else {
// TODO: batch.draw(gpu::TRIANGLE_STRIP, 4);
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
}
glDisable(GL_TEXTURE_2D);
} else {
// TODO: batch.draw(gpu::TRIANGLE_STRIP, 4);
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
}
// TODO: if (!args->_batch) {
// TODO: args->_context->render(batch);
// TODO: }
}
void ImageOverlay::setProperties(const QScriptValue& properties) {

View file

@ -115,7 +115,9 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
thisOverlay->render(renderArgs);
}
}
gpu::GLBackend::renderBatch(batch, true);
renderArgs->_context->syncCache();
renderArgs->_context->render(batch);
}
unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) {

View file

@ -35,14 +35,13 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
if (!_visible) {
return; // do nothing if we're not visible
}
float alpha = getAlpha();
xColor color = getColor();
const float MAX_COLOR = 255.0f;
glm::vec4 rectangleColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
glm::vec3 position = getPosition();
glm::vec3 center = getCenter();
glm::vec2 dimensions = getDimensions();
glm::vec2 halfDimensions = dimensions * 0.5f;
glm::quat rotation = getRotation();
@ -67,7 +66,7 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
glm::vec3 point2(halfDimensions.x, -halfDimensions.y, 0.0f);
glm::vec3 point3(halfDimensions.x, halfDimensions.y, 0.0f);
glm::vec3 point4(-halfDimensions.x, halfDimensions.y, 0.0f);
geometryCache->renderDashedLine(*batch, point1, point2, rectangleColor);
geometryCache->renderDashedLine(*batch, point2, point3, rectangleColor);
geometryCache->renderDashedLine(*batch, point3, point4, rectangleColor);

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QtCore/QDataStream>
#include <NodeList.h>
#include <PacketHeaders.h>
#include <SharedUtil.h>

View file

@ -93,16 +93,18 @@ void EntityTreeRenderer::clear() {
foreach (const EntityItemID& entityID, _entityScripts.keys()) {
checkAndCallUnload(entityID);
}
OctreeRenderer::clear();
_entityScripts.clear();
auto scene = _viewState->getMain3DScene();
render::PendingChanges pendingChanges;
foreach(auto entity, _entitiesInScene) {
entity->removeFromScene(entity, scene, pendingChanges);
}
scene->enqueuePendingChanges(pendingChanges);
_entitiesInScene.clear();
OctreeRenderer::clear();
}
void EntityTreeRenderer::init() {
@ -803,7 +805,7 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity);
connect(&(*DependencyManager::get<SceneScriptingInterface>()), &SceneScriptingInterface::shouldRenderEntitiesChanged, this, &EntityTreeRenderer::updateEntityRenderStatus, Qt::QueuedConnection);
connect(DependencyManager::get<SceneScriptingInterface>().data(), &SceneScriptingInterface::shouldRenderEntitiesChanged, this, &EntityTreeRenderer::updateEntityRenderStatus, Qt::QueuedConnection);
}
QScriptValueList EntityTreeRenderer::createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID) {
@ -1003,7 +1005,7 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
checkAndCallUnload(entityID);
}
_entityScripts.remove(entityID);
// here's where we remove the entity payload from the scene
if (_entitiesInScene.contains(entityID)) {
auto entity = _entitiesInScene.take(entityID);
@ -1164,6 +1166,7 @@ void EntityTreeRenderer::updateEntityRenderStatus(bool shouldRenderEntities) {
} else {
_entityIDsLastInScene = _entitiesInScene.keys();
for (auto entityID : _entityIDsLastInScene) {
// FIXME - is this really right? do we want to do the deletingEntity() code or just remove from the scene.
deletingEntity(entityID);
}
}

View file

@ -189,6 +189,7 @@ void makeEntityItemStatusGetters(RenderableModelEntityItem* entity, render::Item
bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
render::PendingChanges& pendingChanges) {
_myMetaItem = scene->allocateID();
auto renderData = RenderableModelEntityItemMeta::Pointer(new RenderableModelEntityItemMeta(self));
@ -199,7 +200,10 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p
if (_model) {
render::Item::Status::Getters statusGetters;
makeEntityItemStatusGetters(this, statusGetters);
return _model->addToScene(scene, pendingChanges, statusGetters);
// note: we don't care if the model fails to add items, we always added our meta item and therefore we return
// true so that the system knows our meta item is in the scene!
_model->addToScene(scene, pendingChanges, statusGetters);
}
return true;

View file

@ -50,7 +50,7 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
if (textured) {
batch.setUniformTexture(0, _texture->getGPUTexture());
batch.setResourceTexture(0, _texture->getGPUTexture());
}
batch.setModelTransform(getTransformToCenter());
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, textured);

View file

@ -127,21 +127,21 @@ glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVarian
qDebug() << objectName << "requires argument:" << argumentName;
}
ok = false;
return glm::vec3();
return glm::vec3(0.0f);
}
QVariant resultV = arguments[argumentName];
if (resultV.type() != (QVariant::Type) QMetaType::QVariantMap) {
qDebug() << objectName << "argument" << argumentName << "must be a map";
ok = false;
return glm::vec3();
return glm::vec3(0.0f);
}
QVariantMap resultVM = resultV.toMap();
if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z")) {
qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z";
qDebug() << objectName << "argument" << argumentName << "must be a map with keys: x, y, z";
ok = false;
return glm::vec3();
return glm::vec3(0.0f);
}
QVariant xV = resultVM["x"];
@ -155,9 +155,15 @@ glm::vec3 EntityActionInterface::extractVec3Argument(QString objectName, QVarian
float y = yV.toFloat(&yOk);
float z = zV.toFloat(&zOk);
if (!xOk || !yOk || !zOk) {
qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z and values of type float.";
qDebug() << objectName << "argument" << argumentName << "must be a map with keys: x, y, and z of type float.";
ok = false;
return glm::vec3();
return glm::vec3(0.0f);
}
if (x != x || y != y || z != z) {
// at least one of the values is NaN
ok = false;
return glm::vec3(0.0f);
}
return glm::vec3(x, y, z);
@ -181,8 +187,8 @@ glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVarian
}
QVariantMap resultVM = resultV.toMap();
if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z")) {
qDebug() << objectName << "argument" << argumentName << "must be a map with keys of x, y, z";
if (!resultVM.contains("x") || !resultVM.contains("y") || !resultVM.contains("z") || !resultVM.contains("w")) {
qDebug() << objectName << "argument" << argumentName << "must be a map with keys: x, y, z, and w";
ok = false;
return glm::quat();
}
@ -202,12 +208,18 @@ glm::quat EntityActionInterface::extractQuatArgument(QString objectName, QVarian
float w = wV.toFloat(&wOk);
if (!xOk || !yOk || !zOk || !wOk) {
qDebug() << objectName << "argument" << argumentName
<< "must be a map with keys of x, y, z, w and values of type float.";
<< "must be a map with keys: x, y, z, and w of type float.";
ok = false;
return glm::quat();
}
return glm::quat(w, x, y, z);
if (x != x || y != y || z != z || w != w) {
// at least one of the components is NaN!
ok = false;
return glm::quat();
}
return glm::normalize(glm::quat(w, x, y, z));
}
float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMap arguments,
@ -224,7 +236,7 @@ float EntityActionInterface::extractFloatArgument(QString objectName, QVariantMa
bool vOk = true;
float v = vV.toFloat(&vOk);
if (!vOk) {
if (!vOk || v != v) {
ok = false;
return 0.0f;
}

View file

@ -385,7 +385,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += encodedID.size();
bytesRead += encodedID.size();
Q_ASSERT(id == _id);
Q_ASSERT(parser.offset() == bytesRead);
Q_ASSERT(parser.offset() == (unsigned int) bytesRead);
}
#endif
@ -400,8 +400,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
quint32 type = typeCoder;
EntityTypes::EntityType oldType = (EntityTypes::EntityType)type;
Q_ASSERT(oldType == _type);
Q_ASSERT(parser.offset() == bytesRead);
#endif
Q_ASSERT(parser.offset() == (unsigned int) bytesRead);
#endif
bool overwriteLocalData = true; // assume the new content overwrites our local data
quint64 now = usecTimestampNow();
@ -417,9 +417,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += sizeof(createdFromBuffer2);
bytesRead += sizeof(createdFromBuffer2);
Q_ASSERT(createdFromBuffer2 == createdFromBuffer);
Q_ASSERT(parser.offset() == bytesRead);
Q_ASSERT(parser.offset() == (unsigned int) bytesRead);
}
#endif
#endif
if (_created == UNKNOWN_CREATED_TIME) {
// we don't yet have a _created timestamp, so we accept this one
createdFromBuffer -= clockSkew;
@ -458,9 +458,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += sizeof(lastEditedFromBuffer2);
bytesRead += sizeof(lastEditedFromBuffer2);
Q_ASSERT(lastEditedFromBuffer2 == lastEditedFromBuffer);
Q_ASSERT(parser.offset() == bytesRead);
Q_ASSERT(parser.offset() == (unsigned int) bytesRead);
}
#endif
#endif
quint64 lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
if (lastEditedFromBufferAdjusted > now) {
lastEditedFromBufferAdjusted = now;
@ -534,10 +534,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
encodedUpdateDelta = updateDeltaCoder; // determine true length
dataAt += encodedUpdateDelta.size();
bytesRead += encodedUpdateDelta.size();
Q_ASSERT(parser.offset() == bytesRead);
Q_ASSERT(parser.offset() == (unsigned int) bytesRead);
}
#endif
#endif
if (overwriteLocalData) {
_lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that
#ifdef WANT_DEBUG
@ -562,7 +562,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
encodedSimulatedDelta = simulatedDeltaCoder; // determine true length
dataAt += encodedSimulatedDelta.size();
bytesRead += encodedSimulatedDelta.size();
Q_ASSERT(parser.offset() == bytesRead);
Q_ASSERT(parser.offset() == (unsigned int) bytesRead);
}
#endif
@ -599,7 +599,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
dataAt += propertyFlags.getEncodedLength();
bytesRead += propertyFlags.getEncodedLength();
Q_ASSERT(propertyFlags2 == propertyFlags);
Q_ASSERT(parser.offset() == bytesRead);
Q_ASSERT(parser.offset() == (unsigned int)bytesRead);
}
#endif
@ -610,6 +610,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
int bytesRead = parser.offset();
#endif
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID();
bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE) {
// pack SimulationOwner and terse update properties near each other
@ -632,10 +635,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
}
{ // When we own the simulation we don't accept updates to the entity's transform/velocities
// but since we're using macros below we have to temporarily modify overwriteLocalData.
auto nodeList = DependencyManager::get<NodeList>();
bool weOwnIt = _simulationOwner.matchesValidID(nodeList->getSessionUUID());
bool oldOverwrite = overwriteLocalData;
overwriteLocalData = overwriteLocalData && !weOwnIt;
overwriteLocalData = overwriteLocalData && !weOwnSimulation;
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
@ -657,6 +658,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
} else {
// legacy order of packing here
// TODO: purge this logic in a few months from now (2015.07)
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
@ -702,7 +704,16 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref);
READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription);
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
{ // When we own the simulation we don't accept updates to the entity's actions
// but since we're using macros below we have to temporarily modify overwriteLocalData.
// NOTE: this prevents userB from adding an action to an object1 when UserA
// has simulation ownership of it.
// TODO: figure out how to allow multiple users to update actions simultaneously
bool oldOverwrite = overwriteLocalData;
overwriteLocalData = overwriteLocalData && !weOwnSimulation;
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
overwriteLocalData = oldOverwrite;
}
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData);
@ -713,7 +724,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
// NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover
// by doing this parsing here... but it's not likely going to fully recover the content.
//
// TODO: Remove this conde once we've sufficiently migrated content past this damaged version
// TODO: Remove this code once we've sufficiently migrated content past this damaged version
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) {
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
}
@ -738,8 +749,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
}
}
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID();
if (overwriteLocalData) {
if (!_simulationOwner.matchesValidID(myNodeID)) {
@ -1496,7 +1505,7 @@ bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer act
bool result = addActionInternal(simulation, action);
if (!result) {
removeAction(simulation, action->getID());
removeActionInternal(action->getID());
}
unlock();
@ -1520,6 +1529,7 @@ bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPoi
QByteArray newDataCache = serializeActions(success);
if (success) {
_allActionsDataCache = newDataCache;
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
}
return success;
}
@ -1537,6 +1547,7 @@ bool EntityItem::updateAction(EntitySimulation* simulation, const QUuid& actionI
bool success = action->updateArguments(arguments);
if (success) {
_allActionsDataCache = serializeActions(success);
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
} else {
qDebug() << "EntityItem::updateAction failed";
}
@ -1572,6 +1583,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s
bool success = true;
_allActionsDataCache = serializeActions(success);
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
return success;
}
return false;
@ -1590,6 +1602,7 @@ bool EntityItem::clearActions(EntitySimulation* simulation) {
// empty _serializedActions means no actions for the EntityItem
_actionsToRemove.clear();
_allActionsDataCache.clear();
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
unlock();
return true;
}

View file

@ -543,6 +543,9 @@ bool EntityScriptingInterface::actionWorker(const QUuid& entityID,
}
bool success = actor(simulation, entity);
if (success) {
_entityTree->entityChanged(entity);
}
_entityTree->unlock();
// transmit the change

View file

@ -227,15 +227,15 @@ void Batch::setUniformBuffer(uint32 slot, const BufferView& view) {
}
void Batch::setUniformTexture(uint32 slot, const TexturePointer& texture) {
ADD_COMMAND(setUniformTexture);
void Batch::setResourceTexture(uint32 slot, const TexturePointer& texture) {
ADD_COMMAND(setResourceTexture);
_params.push_back(_textures.cache(texture));
_params.push_back(slot);
}
void Batch::setUniformTexture(uint32 slot, const TextureView& view) {
setUniformTexture(slot, view._texture);
void Batch::setResourceTexture(uint32 slot, const TextureView& view) {
setResourceTexture(slot, view._texture);
}
void Batch::setFramebuffer(const FramebufferPointer& framebuffer) {

View file

@ -103,8 +103,8 @@ public:
void setUniformBuffer(uint32 slot, const BufferPointer& buffer, Offset offset, Offset size);
void setUniformBuffer(uint32 slot, const BufferView& view); // not a command, just a shortcut from a BufferView
void setUniformTexture(uint32 slot, const TexturePointer& view);
void setUniformTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView
void setResourceTexture(uint32 slot, const TexturePointer& view);
void setResourceTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView
// Framebuffer Stage
void setFramebuffer(const FramebufferPointer& framebuffer);
@ -178,7 +178,7 @@ public:
COMMAND_setStateBlendFactor,
COMMAND_setUniformBuffer,
COMMAND_setUniformTexture,
COMMAND_setResourceTexture,
COMMAND_setFramebuffer,

View file

@ -0,0 +1,22 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// Draw texture 0 fetched at texcoord.xy, Blend with color uniform
//
// Created by Sam Gateau on 7/12/2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
uniform sampler2D colorMap;
uniform vec4 color;
varying vec2 varTexcoord;
void main(void) {
gl_FragColor = texture2D(colorMap, varTexcoord) * color;
}

View file

@ -0,0 +1,39 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// Draw and transform the unit quad [-1,-1 -> 1,1]
// Transform the normalized texcoords [0, 1] to be in the range [texcoordRect.xy, texcoordRect.xy + texcoordRect.zw]
// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed
//
// Created by Sam Gateau on 6/22/2015
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
uniform vec4 texcoordRect;
varying vec2 varTexcoord;
void main(void) {
const vec4 UNIT_QUAD[4] = vec4[4](
vec4(-1.0, -1.0, 0.0, 1.0),
vec4(1.0, -1.0, 0.0, 1.0),
vec4(-1.0, 1.0, 0.0, 1.0),
vec4(1.0, 1.0, 0.0, 1.0)
);
vec4 pos = UNIT_QUAD[gl_VertexID];
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, pos, gl_Position)$>
varTexcoord = ((pos.xy + 1) * 0.5) * texcoordRect.zw + texcoordRect.xy;
}

View file

@ -35,7 +35,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
(&::gpu::GLBackend::do_setStateBlendFactor),
(&::gpu::GLBackend::do_setUniformBuffer),
(&::gpu::GLBackend::do_setUniformTexture),
(&::gpu::GLBackend::do_setResourceTexture),
(&::gpu::GLBackend::do_setFramebuffer),
@ -204,7 +204,6 @@ void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) {
GLenum mode = _primitiveToGLmode[primitiveType];
uint32 numVertices = batch._params[paramOffset + 2]._uint;
uint32 startVertex = batch._params[paramOffset + 1]._uint;
uint32 startInstance = batch._params[paramOffset + 0]._uint;
glDrawArraysInstancedARB(mode, startVertex, numVertices, numInstances);
(void) CHECK_GL_ERROR();
@ -238,7 +237,7 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) {
std::vector<GLenum> drawBuffers;
if (masks & Framebuffer::BUFFER_COLORS) {
for (int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) {
for (unsigned int i = 0; i < Framebuffer::MAX_NUM_RENDER_BUFFERS; i++) {
if (masks & (1 << i)) {
drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i);
}

View file

@ -321,7 +321,7 @@ protected:
// Uniform Stage
void do_setUniformBuffer(Batch& batch, uint32 paramOffset);
void do_setUniformTexture(Batch& batch, uint32 paramOffset);
void do_setResourceTexture(Batch& batch, uint32 paramOffset);
struct UniformStageState {

View file

@ -188,7 +188,7 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) {
(void) CHECK_GL_ERROR();
}
void GLBackend::do_setUniformTexture(Batch& batch, uint32 paramOffset) {
void GLBackend::do_setResourceTexture(Batch& batch, uint32 paramOffset) {
GLuint slot = batch._params[paramOffset + 1]._uint;
TexturePointer uniformTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);

View file

@ -13,14 +13,46 @@
#include "StandardShaderLib.h"
#include "DrawTransformUnitQuad_vert.h"
#include "DrawTexcoordRectTransformUnitQuad_vert.h"
#include "DrawViewportQuadTransformTexcoord_vert.h"
#include "DrawTexture_frag.h"
#include "DrawColoredTexture_frag.h"
using namespace gpu;
ShaderPointer StandardShaderLib::_drawTransformUnitQuadVS;
ShaderPointer StandardShaderLib::_drawTexcoordRectTransformUnitQuadVS;
ShaderPointer StandardShaderLib::_drawViewportQuadTransformTexcoordVS;
ShaderPointer StandardShaderLib::_drawTexturePS;
ShaderPointer StandardShaderLib::_drawColoredTexturePS;
StandardShaderLib::ProgramMap StandardShaderLib::_programs;
ShaderPointer StandardShaderLib::getProgram(GetShader getVS, GetShader getPS) {
auto programIt = _programs.find(std::pair<GetShader, GetShader>(getVS, getPS));
if (programIt != _programs.end()) {
return (*programIt).second;
} else {
auto vs = (getVS)();
auto ps = (getPS)();
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
if (program) {
// Program created, let's try to make it
if (gpu::Shader::makeProgram((*program))) {
// All good, backup and return that program
_programs.insert(ProgramMap::value_type(std::pair<GetShader, GetShader>(getVS, getPS), program));
return program;
} else {
// Failed to make the program probably because vs and ps cannot work together?
}
} else {
// Failed to create the program maybe because ps and vs are not true vertex and pixel shaders?
}
}
return ShaderPointer();
}
ShaderPointer StandardShaderLib::getDrawTransformUnitQuadVS() {
if (!_drawTransformUnitQuadVS) {
@ -29,6 +61,13 @@ ShaderPointer StandardShaderLib::getDrawTransformUnitQuadVS() {
return _drawTransformUnitQuadVS;
}
ShaderPointer StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS() {
if (!_drawTexcoordRectTransformUnitQuadVS) {
_drawTexcoordRectTransformUnitQuadVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawTexcoordRectTransformUnitQuad_vert)));
}
return _drawTexcoordRectTransformUnitQuadVS;
}
ShaderPointer StandardShaderLib::getDrawViewportQuadTransformTexcoordVS() {
if (!_drawViewportQuadTransformTexcoordVS) {
_drawViewportQuadTransformTexcoordVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawViewportQuadTransformTexcoord_vert)));
@ -42,3 +81,10 @@ ShaderPointer StandardShaderLib::getDrawTexturePS() {
}
return _drawTexturePS;
}
ShaderPointer StandardShaderLib::getDrawColoredTexturePS() {
if (!_drawColoredTexturePS) {
_drawColoredTexturePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawColoredTexture_frag)));
}
return _drawColoredTexturePS;
}

View file

@ -14,6 +14,7 @@
#define hifi_gpu_StandardShaderLib_h
#include <assert.h>
#include <map>
#include "Shader.h"
@ -26,16 +27,30 @@ public:
// A texcoord attribute is also generated texcoord = [(0,0),(1,1)]
static ShaderPointer getDrawTransformUnitQuadVS();
// Shader draw the unit quad objectPos = ([(-1,-1),(1,1)]) and transform it by the full model transform stack (Model, View, Proj).
// A texcoord attribute is also generated covering a rect defined from the uniform vec4 texcoordRect: texcoord = [texcoordRect.xy,texcoordRect.xy + texcoordRect.zw]
static ShaderPointer getDrawTexcoordRectTransformUnitQuadVS();
// Shader draws the unit quad in the full viewport clipPos = ([(-1,-1),(1,1)]) and transform the texcoord = [(0,0),(1,1)] by the model transform.
static ShaderPointer getDrawViewportQuadTransformTexcoordVS();
static ShaderPointer getDrawTexturePS();
static ShaderPointer getDrawColoredTexturePS();
// The shader program combining the shaders available above, so they are unique
typedef ShaderPointer (*GetShader) ();
static ShaderPointer getProgram(GetShader vs, GetShader ps);
protected:
static ShaderPointer _drawTransformUnitQuadVS;
static ShaderPointer _drawTexcoordRectTransformUnitQuadVS;
static ShaderPointer _drawViewportQuadTransformTexcoordVS;
static ShaderPointer _drawTexturePS;
static ShaderPointer _drawColoredTexturePS;
typedef std::map<std::pair<GetShader, GetShader>, ShaderPointer> ProgramMap;
static ProgramMap _programs;
};

View file

@ -103,7 +103,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
//batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize());
batch.setInputFormat(theFormat);
batch.setUniformTexture(0, skybox.getCubemap());
batch.setResourceTexture(0, skybox.getCubemap());
batch.draw(gpu::TRIANGLE_STRIP, 4);
}

View file

@ -13,6 +13,7 @@
#include <qjsondocument.h>
#include <QtCore/QDebug>
#include <QtCore/QDataStream>
#include "NetworkLogging.h"
#include "DataServerAccountInfo.h"

View file

@ -12,6 +12,7 @@
#include <math.h>
#include <QtCore/QJsonDocument>
#include <QtCore/QDataStream>
#include "Assignment.h"
#include "HifiSockAddr.h"

View file

@ -17,6 +17,7 @@
#include <QtCore/QJsonValue>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariantMap>
class JSONBreakableMarshal {
public:

View file

@ -13,6 +13,7 @@
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QDataStream>
#include <SharedUtil.h>
#include <UUID.h>

View file

@ -129,3 +129,10 @@ void ObjectAction::setAngularVelocity(glm::vec3 angularVelocity) {
rigidBody->activate();
}
void ObjectAction::activateBody() {
auto rigidBody = getRigidBody();
if (rigidBody) {
rigidBody->activate();
}
}

View file

@ -55,6 +55,7 @@ protected:
virtual void setLinearVelocity(glm::vec3 linearVelocity);
virtual glm::vec3 getAngularVelocity();
virtual void setAngularVelocity(glm::vec3 angularVelocity);
virtual void activateBody();
void lockForRead() { _lock.lockForRead(); }
bool tryLockForRead() { return _lock.tryLockForRead(); }

View file

@ -59,10 +59,6 @@ void ObjectActionOffset::updateActionWorker(btScalar deltaTimeStep) {
const float MAX_LINEAR_TIMESCALE = 600.0f; // 10 minutes is a long time
if (_positionalTargetSet && _linearTimeScale < MAX_LINEAR_TIMESCALE) {
if (_needsActivation) {
rigidBody->activate();
_needsActivation = false;
}
glm::vec3 objectPosition = bulletToGLM(rigidBody->getCenterOfMassPosition());
glm::vec3 springAxis = objectPosition - _pointToOffsetFrom; // from anchor to object
float distance = glm::length(springAxis);
@ -95,26 +91,21 @@ bool ObjectActionOffset::updateArguments(QVariantMap arguments) {
glm::vec3 pointToOffsetFrom =
EntityActionInterface::extractVec3Argument("offset action", arguments, "pointToOffsetFrom", ok, true);
if (!ok) {
return false;
pointToOffsetFrom = _pointToOffsetFrom;
}
ok = true;
float linearTimeScale =
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearTimeScale", ok, false);
if (ok) {
if (linearTimeScale <= 0.0f) {
qDebug() << "offset action -- linearTimeScale must be greater than zero.";
return false;
}
} else {
linearTimeScale = 0.1f;
if (!ok) {
linearTimeScale = _linearTimeScale;
}
ok = true;
float linearDistance =
EntityActionInterface::extractFloatArgument("offset action", arguments, "linearDistance", ok, false);
if (!ok) {
linearDistance = 0.0f;
linearDistance = _linearDistance;
}
// only change stuff if something actually changed
@ -127,7 +118,7 @@ bool ObjectActionOffset::updateArguments(QVariantMap arguments) {
_linearDistance = linearDistance;
_positionalTargetSet = true;
_active = true;
_needsActivation = true;
activateBody();
unlock();
}
return true;

View file

@ -36,7 +36,6 @@ public:
float _linearDistance;
float _linearTimeScale;
bool _positionalTargetSet;
bool _needsActivation = true;
};
#endif // hifi_ObjectActionOffset_h

View file

@ -17,14 +17,15 @@ const float SPRING_MAX_SPEED = 10.0f;
const uint16_t ObjectActionSpring::springVersion = 1;
ObjectActionSpring::ObjectActionSpring(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectAction(ACTION_TYPE_SPRING, id, ownerEntity),
_positionalTarget(glm::vec3(0.0f)),
_linearTimeScale(0.2f),
_positionalTargetSet(false),
_linearTimeScale(FLT_MAX),
_positionalTargetSet(true),
_rotationalTarget(glm::quat()),
_angularTimeScale(0.2f),
_rotationalTargetSet(false) {
_angularTimeScale(FLT_MAX),
_rotationalTargetSet(true) {
#if WANT_DEBUG
qDebug() << "ObjectActionSpring::ObjectActionSpring";
#endif
@ -61,130 +62,92 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
return;
}
// handle the linear part
if (_positionalTargetSet) {
// check for NaN
if (_positionalTarget.x != _positionalTarget.x ||
_positionalTarget.y != _positionalTarget.y ||
_positionalTarget.z != _positionalTarget.z) {
qDebug() << "ObjectActionSpring::updateActionWorker -- target position includes NaN";
unlock();
lockForWrite();
_active = false;
unlock();
return;
}
glm::vec3 offset = _positionalTarget - bulletToGLM(rigidBody->getCenterOfMassPosition());
float offsetLength = glm::length(offset);
float speed = offsetLength / _linearTimeScale;
const float MAX_TIMESCALE = 600.0f; // 10 min is a long time
if (_linearTimeScale < MAX_TIMESCALE) {
btVector3 offset = rigidBody->getCenterOfMassPosition() - glmToBullet(_positionalTarget);
float offsetLength = offset.length();
float speed = (offsetLength > FLT_EPSILON) ? glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED) : 0.0f;
// cap speed
if (speed > SPRING_MAX_SPEED) {
speed = SPRING_MAX_SPEED;
}
if (offsetLength > IGNORE_POSITION_DELTA) {
glm::vec3 newVelocity = glm::normalize(offset) * speed;
rigidBody->setLinearVelocity(glmToBullet(newVelocity));
rigidBody->activate();
} else {
rigidBody->setLinearVelocity(glmToBullet(glm::vec3(0.0f)));
}
// this action is aggresively critically damped and defeats the current velocity
rigidBody->setLinearVelocity((- speed / offsetLength) * offset);
}
// handle rotation
if (_rotationalTargetSet) {
if (_rotationalTarget.x != _rotationalTarget.x ||
_rotationalTarget.y != _rotationalTarget.y ||
_rotationalTarget.z != _rotationalTarget.z ||
_rotationalTarget.w != _rotationalTarget.w) {
qDebug() << "AvatarActionHold::updateActionWorker -- target rotation includes NaN";
unlock();
lockForWrite();
_active = false;
unlock();
return;
}
if (_angularTimeScale < MAX_TIMESCALE) {
btVector3 targetVelocity(0.0f, 0.0f, 0.0f);
glm::quat bodyRotation = bulletToGLM(rigidBody->getOrientation());
// if qZero and qOne are too close to each other, we can get NaN for angle.
auto alignmentDot = glm::dot(bodyRotation, _rotationalTarget);
const float almostOne = 0.99999f;
if (glm::abs(alignmentDot) < almostOne) {
glm::quat target = _rotationalTarget;
if (alignmentDot < 0) {
btQuaternion bodyRotation = rigidBody->getOrientation();
auto alignmentDot = bodyRotation.dot(glmToBullet(_rotationalTarget));
const float ALMOST_ONE = 0.99999f;
if (glm::abs(alignmentDot) < ALMOST_ONE) {
btQuaternion target = glmToBullet(_rotationalTarget);
if (alignmentDot < 0.0f) {
target = -target;
}
glm::quat qZeroInverse = glm::inverse(bodyRotation);
glm::quat deltaQ = target * qZeroInverse;
glm::vec3 axis = glm::axis(deltaQ);
float angle = glm::angle(deltaQ);
assert(!isNaN(angle));
glm::vec3 newAngularVelocity = (angle / _angularTimeScale) * glm::normalize(axis);
rigidBody->setAngularVelocity(glmToBullet(newAngularVelocity));
rigidBody->activate();
} else {
rigidBody->setAngularVelocity(glmToBullet(glm::vec3(0.0f)));
// if dQ is the incremental rotation that gets an object from Q0 to Q1 then:
//
// Q1 = dQ * Q0
//
// solving for dQ gives:
//
// dQ = Q1 * Q0^
btQuaternion deltaQ = target * bodyRotation.inverse();
float angle = deltaQ.getAngle();
const float MIN_ANGLE = 1.0e-4;
if (angle > MIN_ANGLE) {
targetVelocity = (angle / _angularTimeScale) * deltaQ.getAxis();
}
}
// this action is aggresively critically damped and defeats the current velocity
rigidBody->setAngularVelocity(targetVelocity);
}
unlock();
}
const float MIN_TIMESCALE = 0.1f;
bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
// targets are required, spring-constants are optional
bool ptOk = true;
bool ok = true;
glm::vec3 positionalTarget =
EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ptOk, false);
bool pscOk = true;
EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ok, false);
if (!ok) {
positionalTarget = _positionalTarget;
}
ok = true;
float linearTimeScale =
EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", pscOk, false);
if (ptOk && pscOk && linearTimeScale <= 0.0f) {
qDebug() << "spring action -- linearTimeScale must be greater than zero.";
return false;
EntityActionInterface::extractFloatArgument("spring action", arguments, "linearTimeScale", ok, false);
if (!ok || linearTimeScale <= 0.0f) {
linearTimeScale = _linearTimeScale;
}
bool rtOk = true;
ok = true;
glm::quat rotationalTarget =
EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", rtOk, false);
bool rscOk = true;
EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", ok, false);
if (!ok) {
rotationalTarget = _rotationalTarget;
}
ok = true;
float angularTimeScale =
EntityActionInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", rscOk, false);
if (!ptOk && !rtOk) {
qDebug() << "spring action requires at least one of targetPosition or targetRotation argument";
return false;
EntityActionInterface::extractFloatArgument("spring action", arguments, "angularTimeScale", ok, false);
if (!ok) {
angularTimeScale = _angularTimeScale;
}
lockForWrite();
_positionalTargetSet = _rotationalTargetSet = false;
if (ptOk) {
if (positionalTarget != _positionalTarget
|| linearTimeScale != _linearTimeScale
|| rotationalTarget != _rotationalTarget
|| angularTimeScale != _angularTimeScale) {
// something changed
lockForWrite();
_positionalTarget = positionalTarget;
_positionalTargetSet = true;
if (pscOk) {
_linearTimeScale = linearTimeScale;
} else {
_linearTimeScale = 0.1f;
}
}
if (rtOk) {
_linearTimeScale = glm::max(MIN_TIMESCALE, glm::abs(linearTimeScale));
_rotationalTarget = rotationalTarget;
_rotationalTargetSet = true;
if (rscOk) {
_angularTimeScale = angularTimeScale;
} else {
_angularTimeScale = 0.1f;
}
_angularTimeScale = glm::max(MIN_TIMESCALE, glm::abs(angularTimeScale));
_active = true;
activateBody();
unlock();
}
_active = true;
unlock();
return true;
}
@ -192,15 +155,11 @@ QVariantMap ObjectActionSpring::getArguments() {
QVariantMap arguments;
lockForRead();
if (_positionalTargetSet) {
arguments["linearTimeScale"] = _linearTimeScale;
arguments["targetPosition"] = glmToQMap(_positionalTarget);
}
arguments["linearTimeScale"] = _linearTimeScale;
arguments["targetPosition"] = glmToQMap(_positionalTarget);
if (_rotationalTargetSet) {
arguments["targetRotation"] = glmToQMap(_rotationalTarget);
arguments["angularTimeScale"] = _angularTimeScale;
}
arguments["targetRotation"] = glmToQMap(_rotationalTarget);
arguments["angularTimeScale"] = _angularTimeScale;
unlock();
return arguments;
@ -210,7 +169,7 @@ QByteArray ObjectActionSpring::serialize() const {
QByteArray serializedActionArguments;
QDataStream dataStream(&serializedActionArguments, QIODevice::WriteOnly);
dataStream << getType();
dataStream << ACTION_TYPE_SPRING;
dataStream << getID();
dataStream << ObjectActionSpring::springVersion;

View file

@ -114,9 +114,9 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations);
{
auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS();
auto blitProgram = gpu::ShaderPointer(gpu::Shader::createProgram(VSFS, PSBlit));
//auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
//auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS();
auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS);
gpu::Shader::makeProgram(*blitProgram);
gpu::StatePointer blitState = gpu::StatePointer(new gpu::State());
blitState->setBlendFunction(true,
@ -146,7 +146,7 @@ void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured,
if (!config.isTextured()) {
// If it is not textured, bind white texture and keep using textured pipeline
batch.setUniformTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
}
}
@ -243,13 +243,13 @@ void DeferredLightingEffect::render(RenderArgs* args) {
batch.clearColorFramebuffer(freeFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f));
batch.setUniformTexture(0, textureCache->getPrimaryColorTexture());
batch.setResourceTexture(0, textureCache->getPrimaryColorTexture());
batch.setUniformTexture(1, textureCache->getPrimaryNormalTexture());
batch.setResourceTexture(1, textureCache->getPrimaryNormalTexture());
batch.setUniformTexture(2, textureCache->getPrimarySpecularTexture());
batch.setResourceTexture(2, textureCache->getPrimarySpecularTexture());
batch.setUniformTexture(3, textureCache->getPrimaryDepthTexture());
batch.setResourceTexture(3, textureCache->getPrimaryDepthTexture());
// get the viewport side (left, right, both)
int viewport[4];
@ -274,7 +274,7 @@ void DeferredLightingEffect::render(RenderArgs* args) {
const LightLocations* locations = &_directionalLightLocations;
bool shadowsEnabled = _viewState->getShadowsEnabled();
if (shadowsEnabled) {
batch.setUniformTexture(4, textureCache->getShadowFramebuffer()->getDepthStencilBuffer());
batch.setResourceTexture(4, textureCache->getShadowFramebuffer()->getDepthStencilBuffer());
program = _directionalLightShadowMap;
locations = &_directionalLightShadowMapLocations;
@ -328,7 +328,7 @@ void DeferredLightingEffect::render(RenderArgs* args) {
}
if (useSkyboxCubemap) {
batch.setUniformTexture(5, _skybox->getCubemap());
batch.setResourceTexture(5, _skybox->getCubemap());
}
if (locations->lightBufferUnit >= 0) {
@ -377,11 +377,11 @@ void DeferredLightingEffect::render(RenderArgs* args) {
}
if (useSkyboxCubemap) {
batch.setUniformTexture(5, nullptr);
batch.setResourceTexture(5, nullptr);
}
if (shadowsEnabled) {
batch.setUniformTexture(4, nullptr);
batch.setResourceTexture(4, nullptr);
}
glm::vec4 sCoefficients(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f);
@ -474,17 +474,18 @@ void DeferredLightingEffect::render(RenderArgs* args) {
// IN DEBUG: light->setShowContour(true);
batch.setUniformBuffer(_spotLightLocations.lightBufferUnit, light->getSchemaBuffer());
auto eyeLightPos = eyePoint - light->getPosition();
auto eyeHalfPlaneDistance = glm::dot(eyeLightPos, light->getDirection());
const float TANGENT_LENGTH_SCALE = 0.666f;
glm::vec4 coneParam(light->getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tan(0.5 * light->getSpotAngle()), 1.0f);
glm::vec4 coneParam(light->getSpotAngleCosSin(), TANGENT_LENGTH_SCALE * tanf(0.5f * light->getSpotAngle()), 1.0f);
float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION);
// TODO: We shouldn;t have to do that test and use a different volume geometry for when inside the vlight volume,
// we should be able to draw thre same geometry use DepthClamp but for unknown reason it's s not working...
if ((eyeHalfPlaneDistance > -nearRadius) && (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) {
if ((eyeHalfPlaneDistance > -nearRadius) &&
(glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius)) {
coneParam.w = 0.0f;
batch._glUniform4fv(_spotLightLocations.coneParam, 1, reinterpret_cast< const GLfloat* >(&coneParam));
@ -530,10 +531,10 @@ void DeferredLightingEffect::render(RenderArgs* args) {
}
// Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target
batch.setUniformTexture(0, nullptr);
batch.setUniformTexture(1, nullptr);
batch.setUniformTexture(2, nullptr);
batch.setUniformTexture(3, nullptr);
batch.setResourceTexture(0, nullptr);
batch.setResourceTexture(1, nullptr);
batch.setResourceTexture(2, nullptr);
batch.setResourceTexture(3, nullptr);
args->_context->syncCache();
args->_context->render(batch);
@ -551,7 +552,7 @@ void DeferredLightingEffect::copyBack(RenderArgs* args) {
batch.setFramebuffer(textureCache->getPrimaryFramebuffer());
batch.setPipeline(_blitLightBuffer);
batch.setUniformTexture(0, freeFBO->getRenderBuffer(0));
batch.setResourceTexture(0, freeFBO->getRenderBuffer(0));
batch.setProjectionTransform(glm::mat4());
batch.setViewTransform(Transform());

View file

@ -2066,10 +2066,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
}
static bool showDiffuse = true;
if (showDiffuse && diffuseMap) {
batch.setUniformTexture(0, diffuseMap->getGPUTexture());
batch.setResourceTexture(0, diffuseMap->getGPUTexture());
} else {
batch.setUniformTexture(0, textureCache->getWhiteTexture());
batch.setResourceTexture(0, textureCache->getWhiteTexture());
}
if (locations->texcoordMatrices >= 0) {
@ -2085,14 +2085,14 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
if (!mesh.tangents.isEmpty()) {
Texture* normalMap = networkPart.normalTexture.data();
batch.setUniformTexture(1, !normalMap ?
batch.setResourceTexture(1, !normalMap ?
textureCache->getBlueTexture() : normalMap->getGPUTexture());
}
if (locations->specularTextureUnit >= 0) {
Texture* specularMap = networkPart.specularTexture.data();
batch.setUniformTexture(locations->specularTextureUnit, !specularMap ?
batch.setResourceTexture(locations->specularTextureUnit, !specularMap ?
textureCache->getWhiteTexture() : specularMap->getGPUTexture());
}
@ -2109,7 +2109,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale);
Texture* emissiveMap = networkPart.emissiveTexture.data();
batch.setUniformTexture(locations->emissiveTextureUnit, !emissiveMap ?
batch.setResourceTexture(locations->emissiveTextureUnit, !emissiveMap ?
textureCache->getWhiteTexture() : emissiveMap->getGPUTexture());
}

View file

@ -243,7 +243,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
batch.setViewTransform(viewMat);
batch.setPipeline(getOpaquePipeline());
batch.setUniformTexture(0, args->_whiteTexture);
batch.setResourceTexture(0, args->_whiteTexture);
if (!inItems.empty()) {
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_DEPTH, glm::vec4(), 1.f, 0);

View file

@ -423,7 +423,7 @@ void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str,
setupGPU();
batch.setPipeline(_pipeline);
batch.setUniformTexture(_fontLoc, _texture);
batch.setResourceTexture(_fontLoc, _texture);
batch._glUniform1i(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT));
batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)color);

View file

@ -76,7 +76,7 @@ void Item::Status::Value::setColor(float hue) {
}
void Item::Status::getPackedValues(glm::ivec4& values) const {
for (unsigned int i = 0; i < values.length(); i++) {
for (unsigned int i = 0; i < (unsigned int)values.length(); i++) {
if (i < _values.size()) {
values[i] = _values[i]().getPackedData();
} else {

View file

@ -44,10 +44,7 @@ public:
template <typename T>
inline void readFlags(PropertyFlags<T>& result) {
// FIXME doing heap allocation
QByteArray encoded((const char*)(_data + _offset), remaining());
result.decode(encoded);
_offset += result.getEncodedLength();
_offset += result.decode(_data + _offset, remaining());
}
template<typename T>

View file

@ -25,6 +25,7 @@
#include <QBitArray>
#include <QByteArray>
#include "ByteCountCoding.h"
#include <SharedUtil.h>
template<typename Enum>class PropertyFlags {
@ -51,7 +52,8 @@ public:
void setHasProperty(Enum flag, bool value = true);
bool getHasProperty(Enum flag) const;
QByteArray encode();
void decode(const QByteArray& fromEncoded);
size_t decode(const uint8_t* data, size_t length);
size_t decode(const QByteArray& fromEncoded);
operator QByteArray() { return encode(); };
@ -193,51 +195,62 @@ template<typename Enum> inline QByteArray PropertyFlags<Enum>::encode() {
return output;
}
template<typename Enum> inline void PropertyFlags<Enum>::decode(const QByteArray& fromEncodedBytes) {
template<typename Enum>
inline size_t PropertyFlags<Enum>::decode(const uint8_t* data, size_t size) {
clear(); // we are cleared out!
// first convert the ByteArray into a BitArray...
QBitArray encodedBits;
int bitCount = BITS_PER_BYTE * fromEncodedBytes.count();
encodedBits.resize(bitCount);
for(int byte = 0; byte < fromEncodedBytes.count(); byte++) {
char originalByte = fromEncodedBytes.at(byte);
for(int bit = 0; bit < BITS_PER_BYTE; bit++) {
int shiftBy = BITS_PER_BYTE - (bit + 1);
char maskBit = ( 1 << shiftBy);
bool bitValue = originalByte & maskBit;
encodedBits.setBit(byte * BITS_PER_BYTE + bit, bitValue);
size_t bytesConsumed = 0;
int bitCount = BITS_IN_BYTE * size;
int encodedByteCount = 1; // there is at least 1 byte (after the leadBits)
int leadBits = 1; // there is always at least 1 lead bit
bool inLeadBits = true;
int bitAt = 0;
int expectedBitCount; // unknown at this point
int lastValueBit;
for (unsigned int byte = 0; byte < size; byte++) {
char originalByte = data[byte];
bytesConsumed++;
unsigned char maskBit = 0x80; // LEFT MOST BIT set
for (int bit = 0; bit < BITS_IN_BYTE; bit++) {
bool bitIsSet = originalByte & maskBit;
// Processing of the lead bits
if (inLeadBits) {
if (bitIsSet) {
encodedByteCount++;
leadBits++;
} else {
inLeadBits = false; // once we hit our first 0, we know we're out of the lead bits
expectedBitCount = (encodedByteCount * BITS_IN_BYTE) - leadBits;
lastValueBit = expectedBitCount + bitAt;
// check to see if the remainder of our buffer is sufficient
if (expectedBitCount > (bitCount - leadBits)) {
break;
}
}
} else {
if (bitAt > lastValueBit) {
break;
}
if (bitIsSet) {
setHasProperty(static_cast<Enum>(bitAt - leadBits), true);
}
}
bitAt++;
maskBit >>= 1;
}
}
// next, read the leading bits to determine the correct number of bytes to decode (may not match the QByteArray)
int encodedByteCount = 0;
int leadBits = 1;
int bitAt;
for (bitAt = 0; bitAt < bitCount; bitAt++) {
if (encodedBits.at(bitAt)) {
encodedByteCount++;
leadBits++;
} else {
if (!inLeadBits && bitAt > lastValueBit) {
break;
}
}
encodedByteCount++; // always at least one byte
_encodedLength = encodedByteCount;
_encodedLength = bytesConsumed;
return bytesConsumed;
}
int expectedBitCount = encodedByteCount * BITS_PER_BYTE;
// Now, keep reading...
if (expectedBitCount <= (encodedBits.size() - leadBits)) {
int flagsStartAt = bitAt + 1;
for (bitAt = flagsStartAt; bitAt < expectedBitCount; bitAt++) {
if (encodedBits.at(bitAt)) {
setHasProperty((Enum)(bitAt - flagsStartAt));
}
}
}
template<typename Enum> inline size_t PropertyFlags<Enum>::decode(const QByteArray& fromEncodedBytes) {
return decode(reinterpret_cast<const uint8_t*>(fromEncodedBytes.data()), fromEncodedBytes.size());
}
template<typename Enum> inline void PropertyFlags<Enum>::debugDumpBits() {

View file

@ -102,13 +102,15 @@ class QQuickMenuItem;
QObject* addItem(QObject* parent, const QString& text) {
// FIXME add more checking here to ensure no name conflicts
QQuickMenuItem* returnedValue{ nullptr };
#ifndef QT_NO_DEBUG
bool invokeResult =
#endif
QMetaObject::invokeMethod(parent, "addItem", Qt::DirectConnection, Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
Q_ARG(QString, text));
#ifndef QT_NO_DEBUG
Q_ASSERT(invokeResult);
#else
Q_UNUSED(invokeResult);
#endif
QObject* result = reinterpret_cast<QObject*>(returnedValue);
return result;
}
@ -206,12 +208,14 @@ void VrMenu::insertAction(QAction* before, QAction* action) {
result = ::addItem(menu, action->text());
} else {
QQuickMenuItem* returnedValue{ nullptr };
#ifndef QT_NO_DEBUG
bool invokeResult =
#endif
QMetaObject::invokeMethod(menu, "insertItem", Qt::DirectConnection, Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
Q_ARG(int, index), Q_ARG(QString, action->text()));
#ifndef QT_NO_DEBUG
Q_ASSERT(invokeResult);
#else
Q_UNUSED(invokeResult);
#endif
result = reinterpret_cast<QObject*>(returnedValue);
}
Q_ASSERT(result);

View file

@ -0,0 +1,12 @@
set(TARGET_NAME "entities-test")
# This is not a testcase -- just set it up as a regular hifi project
setup_hifi_project(Network Script)
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
# link in the shared libraries
link_hifi_libraries(entities avatars shared octree gpu model fbx networking animation environment)
copy_dlls_beside_windows_executable()

BIN
tests/entities/packet.bin Normal file

Binary file not shown.

173
tests/entities/src/main.cpp Normal file
View file

@ -0,0 +1,173 @@
//
// main.cpp
// tests/render-utils/src
//
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QCoreApplication>
#include <QFile>
#include <QTimer>
#include <QElapsedTimer>
#include <QLoggingCategory>
#include <QDir>
#include <ByteCountCoding.h>
#include <PathUtils.h>
#include <BoxEntityItem.h>
#include <Octree.h>
const QString& getTestResourceDir() {
static QString dir;
if (dir.isEmpty()) {
QDir path(__FILE__);
path.cdUp();
dir = path.cleanPath(path.absoluteFilePath("../")) + "/";
qDebug() << "Qml Test Path: " << dir;
}
return dir;
}
class StopWatch {
public:
void start() {
Q_ASSERT(_start == 0);
_start = usecTimestampNow();
}
void stop() {
Q_ASSERT(_start != 0);
_last = usecTimestampNow() - _start;
_start = 0;
_total += _last;
_count++;
}
quint64 getLast() {
return _last;
}
quint64 getTotal() {
return _total;
}
float getAverage() {
return (float)_total / (float)_count;
}
void reset() {
_last = _start = _total = _count = 0;
}
private:
size_t _count{ 0 };
quint64 _total{ 0 };
quint64 _start{ 0 };
quint64 _last{ 0 };
};
template <typename T>
void testByteCountCodedStable(const T& value) {
ByteCountCoded<T> coder((T)value);
auto encoded = coder.encode();
#ifndef QT_NO_DEBUG
auto originalEncodedSize = encoded.size();
#endif
for (int i = 0; i < 10; ++i) {
encoded.append(qrand());
}
ByteCountCoded<T> decoder;
decoder.decode(encoded);
Q_ASSERT(decoder.data == coder.data);
#ifndef QT_NO_DEBUG
auto consumed = decoder.decode(encoded.data(), encoded.size());
#endif
Q_ASSERT(consumed == (unsigned int)originalEncodedSize);
}
template <typename T>
void testByteCountCoded() {
testByteCountCodedStable<T>(0);
testByteCountCodedStable<T>(1);
testByteCountCodedStable<T>(1 << 16);
testByteCountCodedStable<T>(std::numeric_limits<T>::max() >> 16);
testByteCountCodedStable<T>(std::numeric_limits<T>::max() >> 8);
testByteCountCodedStable<T>(std::numeric_limits<T>::max() >> 1);
testByteCountCodedStable<T>(std::numeric_limits<T>::max());
}
void testPropertyFlags(uint32_t value) {
EntityPropertyFlags original;
original.clear();
auto enumSize = sizeof(EntityPropertyList);
for (size_t i = 0; i < enumSize * 8; ++i) {
original.setHasProperty((EntityPropertyList)i);
}
QByteArray encoded = original.encode();
#ifndef QT_NO_DEBUG
auto originalSize = encoded.size();
#endif
for (size_t i = 0; i < enumSize; ++i) {
encoded.append(qrand());
}
EntityPropertyFlags decodeOld, decodeNew;
{
decodeOld.decode(encoded);
Q_ASSERT(decodeOld == original);
}
{
#ifndef QT_NO_DEBUG
auto decodeSize = decodeNew.decode((const uint8_t*)encoded.data(), encoded.size());
#endif
Q_ASSERT(originalSize == decodeSize);
Q_ASSERT(decodeNew == original);
}
}
void testPropertyFlags() {
testPropertyFlags(0);
testPropertyFlags(1);
testPropertyFlags(1 << 16);
testPropertyFlags(0xFFFF);
}
int main(int argc, char** argv) {
QCoreApplication app(argc, argv);
{
auto start = usecTimestampNow();
for (int i = 0; i < 1000; ++i) {
testPropertyFlags();
testByteCountCoded<quint8>();
testByteCountCoded<quint16>();
testByteCountCoded<quint32>();
testByteCountCoded<quint64>();
}
auto duration = usecTimestampNow() - start;
qDebug() << duration;
}
DependencyManager::set<NodeList>(NodeType::Unassigned);
QFile file(getTestResourceDir() + "packet.bin");
if (!file.open(QIODevice::ReadOnly)) return -1;
QByteArray packet = file.readAll();
EntityItemPointer item = BoxEntityItem::factory(EntityItemID(), EntityItemProperties());
ReadBitstreamToTreeParams params;
params.bitstreamVersion = 33;
auto start = usecTimestampNow();
for (int i = 0; i < 1000; ++i) {
item->readEntityDataFromBuffer(reinterpret_cast<const unsigned char*>(packet.constData()), packet.size(), params);
}
float duration = (usecTimestampNow() - start);
qDebug() << (duration / 1000.0f);
return 0;
}
#include "main.moc"

View file

@ -125,7 +125,6 @@ public:
DisplayModelElementProxy,
DisplayDebugTimingDetails,
DontDoPrecisionPicking,
DontFadeOnOctreeServerChanges,
DontRenderEntitiesAsScene,
EchoLocalAudio,
EchoServerAudio,