diff --git a/examples/dialTone.js b/examples/dialTone.js
new file mode 100644
index 0000000000..135acb17f4
--- /dev/null
+++ b/examples/dialTone.js
@@ -0,0 +1,23 @@
+//
+// dialTone.js
+// examples
+//
+// Created by Stephen Birarda on 06/08/15.
+// 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
+//
+
+// setup the local sound we're going to use
+var connectSound = SoundCache.getSound("file://" + Paths.resources + "sounds/short1.wav");
+
+// setup the options needed for that sound
+var connectSoundOptions = {
+ localOnly: true
+}
+
+// play the sound locally once we get the first audio packet from a mixer
+Audio.receivedFirstPacket.connect(function(){
+ Audio.playSound(connectSound, connectSoundOptions);
+});
diff --git a/examples/example/dynamicLandscape.js b/examples/example/dynamicLandscape.js
new file mode 100644
index 0000000000..ad247963fd
--- /dev/null
+++ b/examples/example/dynamicLandscape.js
@@ -0,0 +1,89 @@
+
+// dynamicLandscape.js
+// examples
+//
+// Created by Eric Levin on June 8
+// Copyright 2015 High Fidelity, Inc.
+//
+// Meditative ocean landscape
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+
+HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
+Script.include(HIFI_PUBLIC_BUCKET + 'scripts/utilities.js')
+
+var NUM_ROWS = 10;
+var CUBE_SIZE = 1;
+var cubes = [];
+var cubesSettings = [];
+var time = 0;
+
+var OMEGA = 2.0 * Math.PI/8;
+var RANGE = CUBE_SIZE/2;
+
+var center = Vec3.sum(MyAvatar.position, Vec3.multiply(CUBE_SIZE* 10, Quat.getFront(Camera.getOrientation())));
+
+
+for (var x = 0, rowIndex = 0; x < NUM_ROWS * CUBE_SIZE; x += CUBE_SIZE, rowIndex++) {
+ for (var z = 0, columnIndex = 0; z < NUM_ROWS * CUBE_SIZE; z += CUBE_SIZE, columnIndex++) {
+
+ var baseHeight = map( columnIndex + 1, 1, NUM_ROWS, -CUBE_SIZE * 2, -CUBE_SIZE);
+ var relativePosition = {
+ x: x,
+ y: baseHeight,
+ z: z
+ };
+ var position = Vec3.sum(center, relativePosition);
+ cubes.push(Entities.addEntity({
+ type: 'Box',
+ position: position,
+ dimensions: {
+ x: CUBE_SIZE,
+ y: CUBE_SIZE,
+ z: CUBE_SIZE
+ }
+ }));
+
+ var phase = map( (columnIndex + 1) * (rowIndex + 1), 2, NUM_ROWS * NUM_ROWS, Math.PI * 2, Math.PI * 4);
+ cubesSettings.push({
+ baseHeight: center.y + baseHeight,
+ phase: phase
+ })
+ }
+}
+
+function update(deleteTime) {
+ time += deleteTime;
+ for (var i = 0; i < cubes.length; i++) {
+ var phase = cubesSettings[i].phase;
+ var props = Entities.getEntityProperties(cubes[i]);
+ var newHeight = Math.sin(time * OMEGA + phase) / 2.0;
+ var hue = map(newHeight, -.5, .5, 0.5, 0.7);
+ var light = map(newHeight, -.5, .5, 0.4, 0.6)
+ newHeight = cubesSettings[i].baseHeight + (newHeight * RANGE);
+ var newVelocityY = Math.cos(time * OMEGA + phase) / 2.0 * RANGE * OMEGA;
+
+ var newPosition = props.position;
+ var newVelocity = props.velocity;
+
+ newPosition.y = newHeight;
+ newVelocity = newVelocityY;
+ Entities.editEntity( cubes[i], {
+ position: newPosition,
+ velocity: props.velocity,
+ color: hslToRgb({hue: hue, sat: 0.7, light: light})
+ });
+ }
+}
+
+function cleanup() {
+ cubes.forEach(function(cube) {
+ Entities.deleteEntity(cube);
+ })
+}
+
+Script.update.connect(update);
+Script.scriptEnding.connect(cleanup)
+
+
diff --git a/examples/grab.js b/examples/grab.js
index 3d95592068..306af86c68 100644
--- a/examples/grab.js
+++ b/examples/grab.js
@@ -1,4 +1,3 @@
-
// grab.js
// examples
//
@@ -11,247 +10,335 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
-var isGrabbing = false;
-var grabbedEntity = null;
-var actionID = null;
-var prevMouse = {};
-var deltaMouse = {
- z: 0
-}
-var entityProps;
-var moveUpDown = false;
+var MOVE_TIMESCALE = 0.1;
+var INV_MOVE_TIMESCALE = 1.0 / MOVE_TIMESCALE;
+var MAX_SOLID_ANGLE = 0.01; // objects that appear smaller than this can't be grabbed
var CLOSE_ENOUGH = 0.001;
-var FULL_STRENGTH = 0.11;
-var SPRING_RATE = 1.5;
-var DAMPING_RATE = 0.80;
+var ZERO_VEC3 = { x: 0, y: 0, z: 0 };
var ANGULAR_DAMPING_RATE = 0.40;
-var SCREEN_TO_METERS = 0.001;
-var currentPosition, currentVelocity, cameraEntityDistance, currentRotation;
-var velocityTowardTarget, desiredVelocity, addedVelocity, newVelocity, dPosition, camYaw, distanceToTarget, targetPosition;
-var originalGravity = {x: 0, y: 0, z: 0};
-var shouldRotate = false;
-var dQ, theta, axisAngle, dT;
-var angularVelocity = {
- x: 0,
- y: 0,
- z: 0
+
+// NOTE: to improve readability global variable names start with 'g'
+var gIsGrabbing = false;
+var gGrabbedEntity = null;
+var gPrevMouse = {x: 0, y: 0};
+var gEntityProperties;
+var gStartPosition;
+var gStartRotation;
+var gCurrentPosition;
+var gOriginalGravity = ZERO_VEC3;
+var gPlaneNormal = ZERO_VEC3;
+
+// gMaxGrabDistance is a function of the size of the object.
+var gMaxGrabDistance;
+
+// gGrabMode defines the degrees of freedom of the grab target positions
+// relative to gGrabStartPosition options include:
+// xzPlane (default)
+// verticalCylinder (SHIFT)
+// rotate (CONTROL)
+// Modes to eventually support?:
+// xyPlane
+// yzPlane
+// polar
+// 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.
+var gGrabOffset = { x: 0, y: 0, z: 0 };
+
+var gTargetPosition;
+var gTargetRotation;
+var gLiftKey = false; // SHIFT
+var gRotateKey = false; // CONTROL
+
+var gPreviousMouse = { x: 0, y: 0 };
+var gMouseCursorLocation = { x: 0, y: 0 };
+var gMouseAtRotateStart = { x: 0, y: 0 };
+
+var gBeaconHeight = 0.10;
+
+var gAngularVelocity = ZERO_VEC3;
+
+// TODO: play sounds again when we aren't leaking AudioInjector threads
+// var grabSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/CloseClamp.wav");
+// var releaseSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/eric/sounds/ReleaseClamp.wav");
+// var VOLUME = 0.0;
+
+var gBeaconHeight = 0.10;
+var BEACON_COLOR = {
+ red: 200,
+ green: 200,
+ blue: 200
};
+var BEACON_WIDTH = 2;
-var DROP_DISTANCE = 5.0;
-var DROP_COLOR = {
- red: 200,
- green: 200,
- blue: 200
-};
-var DROP_WIDTH = 2;
-
-
-var dropLine = Overlays.addOverlay("line3d", {
- color: DROP_COLOR,
- alpha: 1,
- visible: false,
- lineWidth: DROP_WIDTH
+var gBeacon = Overlays.addOverlay("line3d", {
+ color: BEACON_COLOR,
+ alpha: 1,
+ visible: false,
+ lineWidth: BEACON_WIDTH
});
-
-function vectorIsZero(v) {
- return v.x == 0 && v.y == 0 && v.z == 0;
+function updateDropLine(position) {
+ Overlays.editOverlay(gBeacon, {
+ visible: true,
+ start: {
+ x: position.x,
+ y: position.y + gBeaconHeight,
+ z: position.z
+ },
+ end: {
+ x: position.x,
+ y: position.y - gBeaconHeight,
+ z: position.z
+ }
+ });
}
-function nearLinePoint(targetPosition) {
- // var handPosition = Vec3.sum(MyAvatar.position, {x:0, y:0.2, z:0});
- var handPosition = MyAvatar.getRightPalmPosition();
- var along = Vec3.subtract(targetPosition, handPosition);
- along = Vec3.normalize(along);
- along = Vec3.multiply(along, 0.4);
- return Vec3.sum(handPosition, along);
+function mouseIntersectionWithPlane(pointOnPlane, planeNormal, event) {
+ var cameraPosition = Camera.getPosition();
+ var localPointOnPlane = Vec3.subtract(pointOnPlane, cameraPosition);
+ var distanceFromPlane = Vec3.dot(localPointOnPlane, planeNormal);
+ var MIN_DISTANCE_FROM_PLANE = 0.001;
+ if (Math.abs(distanceFromPlane) < MIN_DISTANCE_FROM_PLANE) {
+ // camera is touching the plane
+ return pointOnPlane;
+ }
+ var pickRay = Camera.computePickRay(event.x, event.y);
+ var dirDotNorm = Vec3.dot(pickRay.direction, planeNormal);
+ var MIN_RAY_PLANE_DOT = 0.00001;
+
+ var localIntersection;
+ var useMaxForwardGrab = false;
+ if (Math.abs(dirDotNorm) > MIN_RAY_PLANE_DOT) {
+ var distanceToIntersection = distanceFromPlane / dirDotNorm;
+ if (distanceToIntersection > 0 && distanceToIntersection < gMaxGrabDistance) {
+ // ray points into the plane
+ localIntersection = Vec3.multiply(pickRay.direction, distanceFromPlane / dirDotNorm);
+ } else {
+ // ray intersects BEHIND the camera or else very far away
+ // so we clamp the grab point to be the maximum forward position
+ useMaxForwardGrab = true;
+ }
+ } else {
+ // ray points perpendicular to grab plane
+ // so we map the grab point to the maximum forward position
+ useMaxForwardGrab = true;
+ }
+ if (useMaxForwardGrab) {
+ // we re-route the intersection to be in front at max distance.
+ var rayDirection = Vec3.subtract(pickRay.direction, Vec3.multiply(planeNormal, dirDotNorm));
+ rayDirection = Vec3.normalize(rayDirection);
+ localIntersection = Vec3.multiply(rayDirection, gMaxGrabDistance);
+ localIntersection = Vec3.sum(localIntersection, Vec3.multiply(planeNormal, distanceFromPlane));
+ }
+ var worldIntersection = Vec3.sum(cameraPosition, localIntersection);
+ return worldIntersection;
}
+function computeNewGrabPlane() {
+ var maybeResetMousePosition = false;
+ if (gGrabMode !== "rotate") {
+ gMouseAtRotateStart = gMouseCursorLocation;
+ } else {
+ maybeResetMousePosition = true;
+ }
+ gGrabMode = "xzPlane";
+ gPointOnPlane = gCurrentPosition;
+ gPlaneNormal = { x: 0, y: 1, z: 0 };
+ if (gLiftKey) {
+ if (!gRotateKey) {
+ gGrabMode = "verticalCylinder";
+ // a new planeNormal will be computed each move
+ }
+ } else if (gRotateKey) {
+ gGrabMode = "rotate";
+ }
+
+ gPointOnPlane = Vec3.subtract(gCurrentPosition, gGrabOffset);
+ var xzOffset = Vec3.subtract(gPointOnPlane, Camera.getPosition());
+ xzOffset.y = 0;
+ gXzDistanceToGrab = Vec3.length(xzOffset);
+
+ if (gGrabMode !== "rotate" && maybeResetMousePosition) {
+ // we reset the mouse position whenever we stop rotating
+ Window.setCursorPosition(gMouseAtRotateStart.x, gMouseAtRotateStart.y);
+ }
+}
function mousePressEvent(event) {
- if (!event.isLeftButton) {
- return;
- }
- var pickRay = Camera.computePickRay(event.x, event.y);
- var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
- if (intersection.intersects && intersection.properties.collisionsWillMove) {
- grabbedEntity = intersection.entityID;
- var props = Entities.getEntityProperties(grabbedEntity)
- isGrabbing = true;
- originalGravity = props.gravity;
- targetPosition = props.position;
- currentPosition = props.position;
- currentVelocity = props.velocity;
- updateDropLine(targetPosition);
-
- Entities.editEntity(grabbedEntity, {
- gravity: {x: 0, y: 0, z: 0}
- });
-
- Controller.mouseMoveEvent.connect(mouseMoveEvent);
- }
-}
-
-function updateDropLine(position) {
- Overlays.editOverlay(dropLine, {
- visible: true,
- start: {
- x: position.x,
- y: position.y + DROP_DISTANCE,
- z: position.z
- },
- end: {
- x: position.x,
- y: position.y - DROP_DISTANCE,
- z: position.z
+ if (!event.isLeftButton) {
+ return;
}
- })
-}
+ gPreviousMouse = {x: event.x, y: event.y };
+ var pickRay = Camera.computePickRay(event.x, event.y);
+ var pickResults = Entities.findRayIntersection(pickRay, true); // accurate picking
+ if (!pickResults.intersects) {
+ // didn't click on anything
+ return;
+ }
+
+ if (!pickResults.properties.collisionsWillMove) {
+ // only grab dynamic objects
+ return;
+ }
+
+ var clickedEntity = pickResults.entityID;
+ var entityProperties = Entities.getEntityProperties(clickedEntity)
+ var objectPosition = entityProperties.position;
+ var cameraPosition = Camera.getPosition();
+
+ gBeaconHeight = Vec3.length(entityProperties.dimensions);
+ gMaxGrabDistance = gBeaconHeight / MAX_SOLID_ANGLE;
+ if (Vec3.distance(objectPosition, cameraPosition) > gMaxGrabDistance) {
+ // don't allow grabs of things far away
+ return;
+ }
+
+ Entities.editEntity(clickedEntity, { gravity: ZERO_VEC3 });
+ gIsGrabbing = true;
+
+ gGrabbedEntity = clickedEntity;
+ gCurrentPosition = entityProperties.position;
+ gOriginalGravity = entityProperties.gravity;
+ gTargetPosition = objectPosition;
+
+ // compute the grab point
+ var nearestPoint = Vec3.subtract(objectPosition, cameraPosition);
+ var distanceToGrab = Vec3.dot(nearestPoint, pickRay.direction);
+ nearestPoint = Vec3.multiply(distanceToGrab, pickRay.direction);
+ gPointOnPlane = Vec3.sum(cameraPosition, nearestPoint);
+
+ // compute the grab offset
+ gGrabOffset = Vec3.subtract(objectPosition, gPointOnPlane);
+
+ computeNewGrabPlane();
+
+ updateDropLine(objectPosition);
+
+ // TODO: play sounds again when we aren't leaking AudioInjector threads
+ //Audio.playSound(grabSound, { position: entityProperties.position, volume: VOLUME });
+}
function mouseReleaseEvent() {
- if (isGrabbing) {
- Controller.mouseMoveEvent.disconnect(mouseMoveEvent);
- isGrabbing = false;
- Entities.deleteAction(grabbedEntity, actionID);
- actionID = null;
+ if (gIsGrabbing) {
+ if (Vec3.length(gOriginalGravity) != 0) {
+ Entities.editEntity(gGrabbedEntity, { gravity: gOriginalGravity });
+ }
- // only restore the original gravity if it's not zero. This is to avoid...
- // 1. interface A grabs an entity and locally saves off its gravity
- // 2. interface A sets the entity's gravity to zero
- // 3. interface B grabs the entity and saves off its gravity (which is zero)
- // 4. interface A releases the entity and puts the original gravity back
- // 5. interface B releases the entity and puts the original gravity back (to zero)
- if (!vectorIsZero(originalGravity)) {
- Entities.editEntity(grabbedEntity, {
- gravity: originalGravity
- });
+ gIsGrabbing = false
+
+ Overlays.editOverlay(gBeacon, { visible: false });
+
+ // TODO: play sounds again when we aren't leaking AudioInjector threads
+ //Audio.playSound(releaseSound, { position: entityProperties.position, volume: VOLUME });
}
-
- Overlays.editOverlay(dropLine, {
- visible: false
- });
- targetPosition = null;
-
- }
}
function mouseMoveEvent(event) {
- if (isGrabbing) {
+ if (!gIsGrabbing) {
+ return;
+ }
+
// see if something added/restored gravity
- var props = Entities.getEntityProperties(grabbedEntity);
- if (!vectorIsZero(props.gravity)) {
- originalGravity = props.gravity;
+ var entityProperties = Entities.getEntityProperties(gGrabbedEntity);
+ if (Vec3.length(entityProperties.gravity) != 0) {
+ gOriginalGravity = entityProperties.gravity;
}
- deltaMouse.x = event.x - prevMouse.x;
- if (!moveUpDown) {
- deltaMouse.z = event.y - prevMouse.y;
- deltaMouse.y = 0;
+ if (gGrabMode === "rotate") {
+ var deltaMouse = { x: 0, y: 0 };
+ var dx = event.x - gPreviousMouse.x;
+ var dy = event.y - gPreviousMouse.y;
+
+ var orientation = Camera.getOrientation();
+ var dragOffset = Vec3.multiply(dx, Quat.getRight(orientation));
+ dragOffset = Vec3.sum(dragOffset, Vec3.multiply(-dy, Quat.getUp(orientation)));
+ var axis = Vec3.cross(dragOffset, Quat.getFront(orientation));
+ var axis = Vec3.normalize(axis);
+ var ROTATE_STRENGTH = 8.0; // magic number tuned by hand
+ gAngularVelocity = Vec3.multiply(ROTATE_STRENGTH, axis);
} else {
- deltaMouse.y = (event.y - prevMouse.y) * -1;
- deltaMouse.z = 0;
+ var newTargetPosition;
+ if (gGrabMode === "verticalCylinder") {
+ // for this mode we recompute the plane based on current Camera
+ var planeNormal = Quat.getFront(Camera.getOrientation());
+ planeNormal.y = 0;
+ planeNormal = Vec3.normalize(planeNormal);
+ var pointOnCylinder = Vec3.multiply(planeNormal, gXzDistanceToGrab);
+ pointOnCylinder = Vec3.sum(Camera.getPosition(), pointOnCylinder);
+ newTargetPosition = mouseIntersectionWithPlane(pointOnCylinder, planeNormal, event);
+ } else {
+ var cameraPosition = Camera.getPosition();
+ newTargetPosition = mouseIntersectionWithPlane(gPointOnPlane, gPlaneNormal, event);
+ var relativePosition = Vec3.subtract(newTargetPosition, cameraPosition);
+ var distance = Vec3.length(relativePosition);
+ if (distance > gMaxGrabDistance) {
+ // clamp distance
+ relativePosition = Vec3.multiply(relativePosition, gMaxGrabDistance / distance);
+ newTargetPosition = Vec3.sum(relativePosition, cameraPosition);
+ }
+ }
+ gTargetPosition = Vec3.sum(newTargetPosition, gGrabOffset);
}
- // Update the target position by the amount the mouse moved
- camYaw = Quat.safeEulerAngles(Camera.getOrientation()).y;
- dPosition = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, camYaw, 0), deltaMouse);
- if (!shouldRotate) {
- // Adjust target position for the object by the mouse move
- cameraEntityDistance = Vec3.distance(Camera.getPosition(), currentPosition);
- // Scale distance we want to move by the distance from the camera to the grabbed object
- // TODO: Correct SCREEN_TO_METERS to be correct for the actual FOV, resolution
- targetPosition = Vec3.sum(targetPosition, Vec3.multiply(dPosition, cameraEntityDistance * SCREEN_TO_METERS));
- } else if (shouldRotate) {
- var transformedDeltaMouse = {
- x: deltaMouse.z,
- y: deltaMouse.x,
- z: deltaMouse.y
- };
- transformedDeltaMouse = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, camYaw, 0), transformedDeltaMouse);
- dQ = Quat.fromVec3Degrees(transformedDeltaMouse);
- theta = 2 * Math.acos(dQ.w);
- axisAngle = Quat.axis(dQ);
- angularVelocity = Vec3.multiply((theta / dT), axisAngle);
- }
- }
- prevMouse.x = event.x;
- prevMouse.y = event.y;
-
+ gPreviousMouse = { x: event.x, y: event.y };
+ gMouseCursorLocation = { x: Window.getCursorPositionX(), y: Window.getCursorPositionY() };
}
-
function keyReleaseEvent(event) {
- if (event.text === "SHIFT") {
- moveUpDown = false;
- }
- if (event.text === "SPACE") {
- shouldRotate = false;
- }
+ if (event.text === "SHIFT") {
+ gLiftKey = false;
+ }
+ if (event.text === "CONTROL") {
+ gRotateKey = false;
+ }
+ computeNewGrabPlane();
}
function keyPressEvent(event) {
- if (event.text === "SHIFT") {
- moveUpDown = true;
- }
- if (event.text === "SPACE") {
- shouldRotate = true;
- }
+ if (event.text === "SHIFT") {
+ gLiftKey = true;
+ }
+ if (event.text === "CONTROL") {
+ gRotateKey = true;
+ }
+ computeNewGrabPlane();
}
function update(deltaTime) {
- dT = deltaTime;
- if (isGrabbing) {
-
- entityProps = Entities.getEntityProperties(grabbedEntity);
- currentPosition = entityProps.position;
- currentVelocity = entityProps.velocity;
- currentRotation = entityProps.rotation;
-
- var dPosition = Vec3.subtract(targetPosition, currentPosition);
-
- distanceToTarget = Vec3.length(dPosition);
- if (distanceToTarget > CLOSE_ENOUGH) {
- // compute current velocity in the direction we want to move
- velocityTowardTarget = Vec3.dot(currentVelocity, Vec3.normalize(dPosition));
- velocityTowardTarget = Vec3.multiply(Vec3.normalize(dPosition), velocityTowardTarget);
- // compute the speed we would like to be going toward the target position
-
- desiredVelocity = Vec3.multiply(dPosition, (1.0 / deltaTime) * SPRING_RATE);
- // compute how much we want to add to the existing velocity
- addedVelocity = Vec3.subtract(desiredVelocity, velocityTowardTarget);
- // If target is too far, roll off the force as inverse square of distance
- if (distanceToTarget / cameraEntityDistance > FULL_STRENGTH) {
- addedVelocity = Vec3.multiply(addedVelocity, Math.pow(FULL_STRENGTH / distanceToTarget, 2.0));
- }
- newVelocity = Vec3.sum(currentVelocity, addedVelocity);
- // Add Damping
- newVelocity = Vec3.subtract(newVelocity, Vec3.multiply(newVelocity, DAMPING_RATE));
- // Update entity
- } else {
- newVelocity = {x: 0, y: 0, z: 0};
- }
- if (shouldRotate) {
- angularVelocity = Vec3.subtract(angularVelocity, Vec3.multiply(angularVelocity, ANGULAR_DAMPING_RATE));
- Entities.editEntity(grabbedEntity, {
- rotation: currentRotation,
- angularVelocity: angularVelocity
- });
- } else {
- angularVelocity = entityProps.angularVelocity;
+ if (!gIsGrabbing) {
+ return;
}
- var newSpeed = Vec3.length(newVelocity);
- if (!actionID) {
- actionID = Entities.addAction("pull-to-point", grabbedEntity, {target: targetPosition, speed: newSpeed});
- } else {
- Entities.updateAction(grabbedEntity, actionID, {target: targetPosition, speed: newSpeed});
- }
+ var entityProperties = Entities.getEntityProperties(gGrabbedEntity);
+ gCurrentPosition = entityProperties.position;
+ if (gGrabMode === "rotate") {
+ gAngularVelocity = Vec3.subtract(gAngularVelocity, Vec3.multiply(gAngularVelocity, ANGULAR_DAMPING_RATE));
+ Entities.editEntity(gGrabbedEntity, { angularVelocity: gAngularVelocity, });
+ }
- updateDropLine(targetPosition);
- }
+ // always push toward linear grab position, even when rotating
+ var newVelocity = ZERO_VEC3;
+ var dPosition = Vec3.subtract(gTargetPosition, gCurrentPosition);
+ var delta = Vec3.length(dPosition);
+ if (delta > CLOSE_ENOUGH) {
+ var MAX_POSITION_DELTA = 4.0;
+ if (delta > MAX_POSITION_DELTA) {
+ dPosition = Vec3.multiply(dPosition, MAX_POSITION_DELTA / delta);
+ }
+ // desired speed is proportional to displacement by the inverse of timescale
+ // (for critically damped motion)
+ newVelocity = Vec3.multiply(dPosition, INV_MOVE_TIMESCALE);
+ }
+ Entities.editEntity(gGrabbedEntity, { velocity: newVelocity, });
+ updateDropLine(gTargetPosition);
}
+Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Controller.keyPressEvent.connect(keyPressEvent);
diff --git a/examples/paint.js b/examples/paint.js
index 6e4438d2ea..8bba4e2571 100644
--- a/examples/paint.js
+++ b/examples/paint.js
@@ -12,7 +12,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include('lineRider.js')
-var MAX_POINTS_PER_LINE = 30;
+var MAX_POINTS_PER_LINE = 80;
var colorPalette = [{
diff --git a/examples/utilities.js b/examples/utilities.js
new file mode 100644
index 0000000000..3844e23e14
--- /dev/null
+++ b/examples/utilities.js
@@ -0,0 +1,56 @@
+// utilities.js
+// examples
+//
+// Created by Eric Levin on June 8
+// Copyright 2015 High Fidelity, Inc.
+//
+// Common utilities
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+
+function hslToRgb(hslColor) {
+ var h = hslColor.hue;
+ var s = hslColor.sat;
+ var l = hslColor.light;
+ var r, g, b;
+
+ if (s == 0) {
+ r = g = b = l; // achromatic
+ } else {
+ var hue2rgb = function hue2rgb(p, q, t) {
+ if (t < 0) t += 1;
+ if (t > 1) t -= 1;
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
+ if (t < 1 / 2) return q;
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
+ return p;
+ }
+
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ var p = 2 * l - q;
+ r = hue2rgb(p, q, h + 1 / 3);
+ g = hue2rgb(p, q, h);
+ b = hue2rgb(p, q, h - 1 / 3);
+ }
+
+ return {
+ red: Math.round(r * 255),
+ green: Math.round(g * 255),
+ blue: Math.round(b * 255)
+ };
+
+}
+
+function map(value, min1, max1, min2, max2) {
+ return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
+}
+
+function randFloat(low, high) {
+ return low + Math.random() * (high - low);
+}
+
+
+function randInt(low, high) {
+ return Math.floor(randFloat(low, high));
+}
\ No newline at end of file
diff --git a/examples/utilities/tools/cookies.js b/examples/utilities/tools/cookies.js
index 0182bf8db0..136b5b7f82 100755
--- a/examples/utilities/tools/cookies.js
+++ b/examples/utilities/tools/cookies.js
@@ -134,7 +134,7 @@ Slider = function(x,y,width,thumbSize) {
}
// The Checkbox class
-Checkbox = function(x,y,width,thumbSize) {
+Checkbox = function(x,y,thumbSize) {
this.thumb = Overlays.addOverlay("text", {
backgroundColor: { red: 255, green: 255, blue: 255 },
@@ -150,7 +150,7 @@ Checkbox = function(x,y,width,thumbSize) {
backgroundColor: { red: 125, green: 125, blue: 255 },
x: x,
y: y,
- width: width,
+ width: thumbSize * 2,
height: thumbSize,
alpha: 1.0,
backgroundAlpha: 0.5,
@@ -161,7 +161,7 @@ Checkbox = function(x,y,width,thumbSize) {
this.thumbHalfSize = 0.5 * thumbSize;
this.minThumbX = x + this.thumbHalfSize;
- this.maxThumbX = x + width - this.thumbHalfSize;
+ this.maxThumbX = x + thumbSize * 2 - this.thumbHalfSize;
this.thumbX = this.minThumbX;
this.minValue = 0.0;
@@ -553,7 +553,7 @@ Panel = function(x, y) {
var item = new PanelItem(name, setValue, getValue, displayValue, this.x, this.nextY, textWidth, valueWidth, rawHeight);
- var checkbox = new Checkbox(this.widgetX, this.nextY, widgetWidth, rawHeight);
+ var checkbox = new Checkbox(this.widgetX, this.nextY, rawHeight);
item.widget = checkbox;
item.widget.onValueChanged = function(value) { item.setterFromWidget(value); };
diff --git a/examples/utilities/tools/renderEngineDebug.js b/examples/utilities/tools/renderEngineDebug.js
new file mode 100755
index 0000000000..79b0010210
--- /dev/null
+++ b/examples/utilities/tools/renderEngineDebug.js
@@ -0,0 +1,104 @@
+//
+// SunLightExample.js
+// examples
+// Sam Gateau
+// 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
+//
+
+Script.include("cookies.js");
+
+var panel = new Panel(10, 400);
+
+panel.newCheckbox("Enable Cull Opaque",
+ function(value) { Scene.setEngineCullOpaque((value != 0)); },
+ function() { return Scene.doEngineCullOpaque(); },
+ function(value) { return (value); }
+);
+
+panel.newCheckbox("Enable Sort Opaque",
+ function(value) { Scene.setEngineSortOpaque((value != 0)); },
+ function() { return Scene.doEngineSortOpaque(); },
+ function(value) { return (value); }
+);
+
+panel.newCheckbox("Enable Render Opaque",
+ function(value) { Scene.setEngineRenderOpaque((value != 0)); },
+ function() { return Scene.doEngineRenderOpaque(); },
+ function(value) { return (value); }
+);
+
+panel.newSlider("Num Feed Opaques", 0, 1000,
+ function(value) { },
+ function() { return Scene.getEngineNumFeedOpaqueItems(); },
+ function(value) { return (value); }
+);
+
+panel.newSlider("Num Drawn Opaques", 0, 1000,
+ function(value) { },
+ function() { return Scene.getEngineNumDrawnOpaqueItems(); },
+ function(value) { return (value); }
+);
+
+panel.newSlider("Max Drawn Opaques", -1, 1000,
+ function(value) { Scene.setEngineMaxDrawnOpaqueItems(value); },
+ function() { return Scene.getEngineMaxDrawnOpaqueItems(); },
+ function(value) { return (value); }
+);
+
+panel.newCheckbox("Enable Cull Transparent",
+ function(value) { Scene.setEngineCullTransparent((value != 0)); },
+ function() { return Scene.doEngineCullTransparent(); },
+ function(value) { return (value); }
+);
+
+panel.newCheckbox("Enable Sort Transparent",
+ function(value) { Scene.setEngineSortTransparent((value != 0)); },
+ function() { return Scene.doEngineSortTransparent(); },
+ function(value) { return (value); }
+);
+
+panel.newCheckbox("Enable Render Transparent",
+ function(value) { Scene.setEngineRenderTransparent((value != 0)); },
+ function() { return Scene.doEngineRenderTransparent(); },
+ function(value) { return (value); }
+);
+
+panel.newSlider("Num Feed Transparents", 0, 100,
+ function(value) { },
+ function() { return Scene.getEngineNumFeedTransparentItems(); },
+ function(value) { return (value); }
+);
+
+panel.newSlider("Num Drawn Transparents", 0, 100,
+ function(value) { },
+ function() { return Scene.getEngineNumDrawnTransparentItems(); },
+ function(value) { return (value); }
+);
+
+panel.newSlider("Max Drawn Transparents", -1, 100,
+ function(value) { Scene.setEngineMaxDrawnTransparentItems(value); },
+ function() { return Scene.getEngineMaxDrawnTransparentItems(); },
+ function(value) { return (value); }
+);
+
+var tickTackPeriod = 500;
+
+function updateCounters() {
+ panel.set("Num Feed Opaques", panel.get("Num Feed Opaques"));
+ panel.set("Num Drawn Opaques", panel.get("Num Drawn Opaques"));
+ panel.set("Num Feed Transparents", panel.get("Num Feed Transparents"));
+ panel.set("Num Drawn Transparents", panel.get("Num Drawn Transparents"));
+}
+Script.setInterval(updateCounters, tickTackPeriod);
+
+Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); });
+Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); });
+Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); });
+
+function scriptEnding() {
+ panel.destroy();
+}
+Script.scriptEnding.connect(scriptEnding);
diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index 2f91cf6a68..dffe0e0398 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -126,7 +126,7 @@ target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS})
# link required hifi libraries
-link_hifi_libraries(shared octree environment gpu model fbx networking entities avatars
+link_hifi_libraries(shared octree environment gpu model render fbx networking entities avatars
audio audio-client animation script-engine physics
render-utils entities-renderer ui plugins display-plugins)
diff --git a/interface/resources/images/hifi-logo-blackish.svg b/interface/resources/images/hifi-logo-blackish.svg
new file mode 100644
index 0000000000..60bfb3d418
--- /dev/null
+++ b/interface/resources/images/hifi-logo-blackish.svg
@@ -0,0 +1,123 @@
+
+
+
+
\ No newline at end of file
diff --git a/interface/resources/images/login-close.svg b/interface/resources/images/login-close.svg
new file mode 100644
index 0000000000..2fb10c241b
--- /dev/null
+++ b/interface/resources/images/login-close.svg
@@ -0,0 +1,55 @@
+
+
\ No newline at end of file
diff --git a/interface/resources/images/login-password.svg b/interface/resources/images/login-password.svg
new file mode 100644
index 0000000000..98d86f6d8a
--- /dev/null
+++ b/interface/resources/images/login-password.svg
@@ -0,0 +1,58 @@
+
+
\ No newline at end of file
diff --git a/interface/resources/images/login-username.svg b/interface/resources/images/login-username.svg
new file mode 100644
index 0000000000..a40dd91cf7
--- /dev/null
+++ b/interface/resources/images/login-username.svg
@@ -0,0 +1,51 @@
+
+
\ No newline at end of file
diff --git a/interface/resources/qml/AddressBarDialog.qml b/interface/resources/qml/AddressBarDialog.qml
index 3e03c01567..3377b20d87 100644
--- a/interface/resources/qml/AddressBarDialog.qml
+++ b/interface/resources/qml/AddressBarDialog.qml
@@ -9,18 +9,16 @@
//
import Hifi 1.0
-import QtQuick 2.3
-import QtQuick.Controls 1.2
+import QtQuick 2.4
import "controls"
import "styles"
-Item {
+DialogContainer {
id: root
HifiConstants { id: hifi }
objectName: "AddressBarDialog"
- property int animationDuration: hifi.effects.fadeInDuration
property bool destroyOnInvisible: false
property real scale: 1.25 // Make this dialog a little larger than normal
@@ -101,57 +99,18 @@ Item {
}
}
- // The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions.
- // Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property
- // that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the
- // visibility.
- enabled: false
- opacity: 0.0
-
onEnabledChanged: {
- opacity = enabled ? 1.0 : 0.0
if (enabled) {
- addressLine.forceActiveFocus();
+ addressLine.forceActiveFocus()
}
}
-
- onParentChanged: {
- if (enabled && visible) {
- addressLine.forceActiveFocus();
- }
- }
-
-
- Behavior on opacity {
- // Animate opacity.
- NumberAnimation {
- duration: animationDuration
- easing.type: Easing.OutCubic
- }
- }
-
- onOpacityChanged: {
- // Once we're transparent, disable the dialog's visibility.
- visible = (opacity != 0.0)
- }
onVisibleChanged: {
if (!visible) {
- reset()
-
- // Some dialogs should be destroyed when they become invisible.
- if (destroyOnInvisible) {
- destroy()
- }
- } else {
- addressLine.forceActiveFocus();
+ addressLine.text = ""
}
}
- function reset() {
- addressLine.text = ""
- }
-
function toggleOrGo() {
if (addressLine.text == "") {
enabled = false
@@ -160,21 +119,18 @@ Item {
}
}
- Keys.onEscapePressed: {
- enabled = false
- }
-
Keys.onPressed: {
- switch(event.key) {
- case Qt.Key_W:
- if (event.modifiers == Qt.ControlModifier) {
- event.accepted = true
- enabled = false
- }
+ switch (event.key) {
+ case Qt.Key_Escape:
+ case Qt.Key_Back:
+ enabled = false
+ event.accepted = true
+ break
+ case Qt.Key_Enter:
+ case Qt.Key_Return:
+ toggleOrGo()
+ event.accepted = true
break
}
}
-
- Keys.onReturnPressed: toggleOrGo()
- Keys.onEnterPressed: toggleOrGo()
}
diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml
index 55a0a6a461..947bf739fc 100644
--- a/interface/resources/qml/Browser.qml
+++ b/interface/resources/qml/Browser.qml
@@ -4,7 +4,7 @@ import QtWebKit 3.0
import "controls"
import "styles"
-Dialog {
+VrDialog {
id: root
HifiConstants { id: hifi }
title: "Browser"
diff --git a/interface/resources/qml/ErrorDialog.qml b/interface/resources/qml/ErrorDialog.qml
index c0f8132f14..76d9111d97 100644
--- a/interface/resources/qml/ErrorDialog.qml
+++ b/interface/resources/qml/ErrorDialog.qml
@@ -8,27 +8,22 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
-import Hifi 1.0 as Hifi
-import QtQuick 2.3
-import QtQuick.Controls 1.2
-import QtQuick.Dialogs 1.2
+import Hifi 1.0
+import QtQuick 2.4
import "controls"
import "styles"
-Item {
+DialogContainer {
id: root
HifiConstants { id: hifi }
- property int animationDuration: hifi.effects.fadeInDuration
- property bool destroyOnInvisible: true
-
Component.onCompleted: {
enabled = true
}
onParentChanged: {
if (visible && enabled) {
- forceActiveFocus();
+ forceActiveFocus()
}
}
@@ -38,7 +33,7 @@ Item {
x: parent ? parent.width / 2 - width / 2 : 0
y: parent ? parent.height / 2 - height / 2 : 0
- Hifi.ErrorDialog {
+ ErrorDialog {
id: content
implicitWidth: box.width
@@ -69,7 +64,7 @@ Item {
Text {
id: messageText
- font.pointSize: 10
+ font.pixelSize: hifi.fonts.pixelSize * 0.6
font.weight: Font.Bold
anchors {
@@ -91,55 +86,17 @@ Item {
}
MouseArea {
anchors.fill: parent
+ cursorShape: "PointingHandCursor"
onClicked: {
- content.accept();
+ content.accept()
}
}
}
}
}
- // The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions.
- // Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property
- // that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the
- // visibility.
- enabled: false
- opacity: 0.0
-
- onEnabledChanged: {
- opacity = enabled ? 1.0 : 0.0
- }
-
- Behavior on opacity {
- // Animate opacity.
- NumberAnimation {
- duration: animationDuration
- easing.type: Easing.OutCubic
- }
- }
-
- onOpacityChanged: {
- // Once we're transparent, disable the dialog's visibility.
- visible = (opacity != 0.0)
- }
-
- onVisibleChanged: {
- if (!visible) {
- // Some dialogs should be destroyed when they become invisible.
- if (destroyOnInvisible) {
- destroy()
- }
- }
- }
-
Keys.onPressed: {
- if (event.modifiers === Qt.ControlModifier)
- switch (event.key) {
- case Qt.Key_W:
- event.accepted = true
- content.accept()
- break
- } else switch (event.key) {
+ switch (event.key) {
case Qt.Key_Escape:
case Qt.Key_Back:
case Qt.Key_Enter:
diff --git a/interface/resources/qml/InfoView.qml b/interface/resources/qml/InfoView.qml
index 6b49e6f0c7..012f04f1fd 100644
--- a/interface/resources/qml/InfoView.qml
+++ b/interface/resources/qml/InfoView.qml
@@ -5,7 +5,7 @@ import QtQuick.Controls.Styles 1.3
import QtWebKit 3.0
import "controls"
-Dialog {
+VrDialog {
id: root
width: 800
height: 800
diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml
index 5653dfc7a1..8d5267f7f8 100644
--- a/interface/resources/qml/LoginDialog.qml
+++ b/interface/resources/qml/LoginDialog.qml
@@ -1,78 +1,173 @@
+//
+// LoginDialog.qml
+//
+// Created by David Rowe on 3 Jun 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
+//
+
import Hifi 1.0
-import QtQuick 2.3
-import QtQuick.Controls.Styles 1.3
+import QtQuick 2.4
import "controls"
import "styles"
-Dialog {
+DialogContainer {
+ id: root
HifiConstants { id: hifi }
- title: "Login"
+
objectName: "LoginDialog"
- height: 512
- width: 384
- onVisibleChanged: {
- if (!visible) {
- reset()
- }
- }
+ property bool destroyOnInvisible: false
- onEnabledChanged: {
- if (enabled) {
- username.forceActiveFocus();
- }
- }
+ implicitWidth: loginDialog.implicitWidth
+ implicitHeight: loginDialog.implicitHeight
- function reset() {
- username.text = ""
- password.text = ""
- loginDialog.statusText = ""
- }
+ 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
LoginDialog {
id: loginDialog
- anchors.fill: parent
- anchors.margins: parent.margins
- anchors.topMargin: parent.topMargin
- Column {
- anchors.topMargin: 8
- anchors.right: parent.right
- anchors.rightMargin: 0
- anchors.left: parent.left
- anchors.top: parent.top
- spacing: 8
- Image {
- height: 64
- anchors.horizontalCenter: parent.horizontalCenter
- width: 64
- source: "../images/hifi-logo.svg"
+ implicitWidth: backgroundRectangle.width
+ implicitHeight: backgroundRectangle.height
+
+ readonly property int inputWidth: 500
+ readonly property int inputHeight: 60
+ readonly property int borderWidth: 30
+ 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
+ width: loginDialog.inputWidth + loginDialog.borderWidth * 2
+ height: loginDialog.inputHeight * 6 + loginDialog.closeMargin * 2
+ radius: loginDialog.closeMargin * 2
+
+ color: "#2c86b1"
+ opacity: 0.85
+
+ 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: closeIcon
+ source: "../images/login-close.svg"
+ width: 20
+ height: 20
+ anchors {
+ top: backgroundRectangle.top
+ right: backgroundRectangle.right
+ topMargin: loginDialog.closeMargin
+ rightMargin: loginDialog.closeMargin
}
- Border {
- width: 304
- height: 64
- anchors.horizontalCenter: parent.horizontalCenter
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: "PointingHandCursor"
+ onClicked: {
+ root.enabled = false
+ }
+ }
+ }
+
+ Column {
+ id: mainContent
+ width: loginDialog.inputWidth
+ spacing: loginDialog.inputSpacing
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ verticalCenter: parent.verticalCenter
+ }
+
+ Item {
+ // Offset content down a little
+ width: loginDialog.inputWidth
+ height: loginDialog.closeMargin
+ }
+
+ Rectangle {
+ width: loginDialog.inputWidth
+ height: loginDialog.inputHeight
+ radius: height / 2
+ color: "#ebebeb"
+
+ Image {
+ source: "../images/login-username.svg"
+ width: loginDialog.inputHeight * 0.65
+ height: width
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ leftMargin: loginDialog.inputHeight / 4
+ }
+ }
+
TextInput {
id: username
- anchors.fill: parent
- helperText: "Username or Email"
- anchors.margins: 8
+ anchors {
+ fill: parent
+ leftMargin: loginDialog.inputHeight
+ rightMargin: loginDialog.inputHeight / 2
+ }
+
+ helperText: "username or email"
+ color: hifi.colors.text
+
KeyNavigation.tab: password
KeyNavigation.backtab: password
}
}
- Border {
- width: 304
- height: 64
- anchors.horizontalCenter: parent.horizontalCenter
+ Rectangle {
+ width: loginDialog.inputWidth
+ height: loginDialog.inputHeight
+ radius: height / 2
+ color: "#ebebeb"
+
+ Image {
+ source: "../images/login-password.svg"
+ width: loginDialog.inputHeight * 0.65
+ height: width
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ leftMargin: loginDialog.inputHeight / 4
+ }
+ }
+
TextInput {
id: password
- anchors.fill: parent
+ anchors {
+ fill: parent
+ leftMargin: loginDialog.inputHeight
+ rightMargin: loginDialog.inputHeight / 2
+ }
+
+ helperText: "password"
echoMode: TextInput.Password
- helperText: "Password"
- anchors.margins: 8
+ color: hifi.colors.text
+
KeyNavigation.tab: username
KeyNavigation.backtab: username
onFocusChanged: {
@@ -83,102 +178,176 @@ Dialog {
}
}
- Text {
- anchors.horizontalCenter: parent.horizontalCenter
- textFormat: Text.StyledText
- width: parent.width
- height: 96
- wrapMode: Text.WordWrap
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
- text: loginDialog.statusText
- }
- }
+ Item {
+ width: loginDialog.inputWidth
+ height: loginDialog.inputHeight / 2
- Column {
- anchors.bottomMargin: 5
- anchors.right: parent.right
- anchors.rightMargin: 0
- anchors.left: parent.left
- anchors.bottom: parent.bottom
+ Text {
+ id: messageText
+
+ visible: loginDialog.statusText != "" && loginDialog.statusText != "Logging in..."
+
+ width: loginDialog.inputWidth
+ height: loginDialog.inputHeight / 2
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ text: loginDialog.statusText
+ color: "white"
+ }
+
+ Row {
+ id: messageSpinner
+
+ visible: loginDialog.statusText == "Logging in..."
+ onVisibleChanged: visible ? messageSpinnerAnimation.restart() : messageSpinnerAnimation.stop()
+
+ spacing: 24
+ anchors {
+ verticalCenter: parent.verticalCenter
+ horizontalCenter: parent.horizontalCenter
+ }
+
+ Rectangle {
+ id: spinner1
+ width: 10
+ height: 10
+ color: "#ebebeb"
+ opacity: 0.05
+ }
+
+ Rectangle {
+ id: spinner2
+ width: 10
+ height: 10
+ color: "#ebebeb"
+ opacity: 0.05
+ }
+
+ Rectangle {
+ id: spinner3
+ width: 10
+ height: 10
+ color: "#ebebeb"
+ opacity: 0.05
+ }
+
+ SequentialAnimation {
+ id: messageSpinnerAnimation
+ running: messageSpinner.visible
+ loops: Animation.Infinite
+ NumberAnimation { target: spinner1; property: "opacity"; to: 1.0; duration: 1000 }
+ NumberAnimation { target: spinner2; property: "opacity"; to: 1.0; duration: 1000 }
+ NumberAnimation { target: spinner3; property: "opacity"; to: 1.0; duration: 1000 }
+ NumberAnimation { target: spinner1; property: "opacity"; to: 0.05; duration: 0 }
+ NumberAnimation { target: spinner2; property: "opacity"; to: 0.05; duration: 0 }
+ NumberAnimation { target: spinner3; property: "opacity"; to: 0.05; duration: 0 }
+ }
+ }
+ }
Rectangle {
- width: 192
- height: 64
- anchors.horizontalCenter: parent.horizontalCenter
- color: hifi.colors.hifiBlue
- border.width: 0
- radius: 10
+ width: loginDialog.inputWidth
+ height: loginDialog.inputHeight
+ radius: height / 2
+ color: "#353535"
+
+ TextInput {
+ anchors.fill: parent
+ text: "Login"
+ color: "white"
+ horizontalAlignment: Text.AlignHCenter
+ }
MouseArea {
- anchors.bottom: parent.bottom
- anchors.bottomMargin: 0
- anchors.top: parent.top
- anchors.right: parent.right
- anchors.left: parent.left
+ anchors.fill: parent
+ cursorShape: "PointingHandCursor"
onClicked: {
loginDialog.login(username.text, password.text)
}
}
+ }
- Row {
- anchors.centerIn: parent
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Text {
+ text: "Password?"
+ font.pixelSize: hifi.fonts.pixelSize * 0.8
+ font.underline: true
+ color: "#e0e0e0"
+ width: loginDialog.inputHeight * 4
+ horizontalAlignment: Text.AlignRight
anchors.verticalCenter: parent.verticalCenter
- spacing: 8
+
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: "PointingHandCursor"
+ onClicked: {
+ loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new")
+ }
+ }
+ }
+
+ Item {
+ width: loginDialog.inputHeight + loginDialog.inputSpacing * 2
+ height: loginDialog.inputHeight
+
Image {
- id: loginIcon
- height: 32
- width: 32
- source: "../images/login.svg"
- }
- Text {
- text: "Login"
- color: "white"
- width: 64
- height: parent.height
+ id: hifiIcon
+ source: "../images/hifi-logo-blackish.svg"
+ width: loginDialog.inputHeight
+ height: width
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ verticalCenter: parent.verticalCenter
+ }
}
}
- }
+ Text {
+ text: "Register"
+ font.pixelSize: hifi.fonts.pixelSize * 0.8
+ font.underline: true
+ color: "#e0e0e0"
+ width: loginDialog.inputHeight * 4
+ horizontalAlignment: Text.AlignLeft
+ anchors.verticalCenter: parent.verticalCenter
- Text {
- width: parent.width
- height: 24
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- text:"Create Account"
- font.pointSize: 12
- font.bold: true
- color: hifi.colors.hifiBlue
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- loginDialog.openUrl(loginDialog.rootUrl + "/signup")
- }
- }
- }
-
- Text {
- width: parent.width
- height: 24
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
- font.pointSize: 12
- text: "Recover Password"
- color: hifi.colors.hifiBlue
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new")
+ MouseArea {
+ anchors.fill: parent
+ cursorShape: "PointingHandCursor"
+ onClicked: {
+ loginDialog.openUrl(loginDialog.rootUrl + "/signup")
+ }
}
}
}
}
}
+
+ onOpacityChanged: {
+ // Set focus once animation is completed so that focus is set at start-up when not logged in
+ if (opacity == 1.0) {
+ username.forceActiveFocus()
+ }
+ }
+
+ onVisibleChanged: {
+ if (!visible) {
+ username.text = ""
+ password.text = ""
+ loginDialog.statusText = ""
+ }
+ }
+
Keys.onPressed: {
- switch(event.key) {
+ switch (event.key) {
+ case Qt.Key_Escape:
+ case Qt.Key_Back:
+ enabled = false
+ event.accepted = true
+ break
case Qt.Key_Enter:
case Qt.Key_Return:
if (username.activeFocus) {
@@ -192,7 +361,7 @@ Dialog {
loginDialog.login(username.text, password.text)
}
}
- break;
+ break
}
}
}
diff --git a/interface/resources/qml/MarketplaceDialog.qml b/interface/resources/qml/MarketplaceDialog.qml
index 58bb3e6183..946f32e84a 100644
--- a/interface/resources/qml/MarketplaceDialog.qml
+++ b/interface/resources/qml/MarketplaceDialog.qml
@@ -5,7 +5,7 @@ import QtQuick.Controls.Styles 1.3
import QtWebKit 3.0
import "controls"
-Dialog {
+VrDialog {
title: "Test Dlg"
id: testDialog
objectName: "Browser"
diff --git a/interface/resources/qml/MessageDialog.qml b/interface/resources/qml/MessageDialog.qml
index dd410b8070..e8b01df9d0 100644
--- a/interface/resources/qml/MessageDialog.qml
+++ b/interface/resources/qml/MessageDialog.qml
@@ -5,7 +5,7 @@ import QtQuick.Dialogs 1.2
import "controls"
import "styles"
-Dialog {
+VrDialog {
id: root
HifiConstants { id: hifi }
property real spacing: hifi.layout.spacing
diff --git a/interface/resources/qml/TestDialog.qml b/interface/resources/qml/TestDialog.qml
index 15bd790c22..e6675b7282 100644
--- a/interface/resources/qml/TestDialog.qml
+++ b/interface/resources/qml/TestDialog.qml
@@ -3,7 +3,7 @@ import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.3
import "controls"
-Dialog {
+VrDialog {
title: "Test Dialog"
id: testDialog
objectName: "TestDialog"
diff --git a/interface/resources/qml/controls/DialogContainer.qml b/interface/resources/qml/controls/DialogContainer.qml
new file mode 100644
index 0000000000..4aa4e45d67
--- /dev/null
+++ b/interface/resources/qml/controls/DialogContainer.qml
@@ -0,0 +1,65 @@
+//
+// DialogCommon.qml
+//
+// Created by David Rowe on 3 Jun 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
+//
+
+import Hifi 1.0
+import QtQuick 2.4
+import "../styles"
+
+Item {
+ id: root
+
+ property bool destroyOnInvisible: true
+
+
+ // The UI enables an object, rather than manipulating its visibility, so that we can do animations in both directions.
+ // Because visibility and enabled are booleans, they cannot be animated. So when enabled is changed, we modify a property
+ // that can be animated, like scale or opacity, and then when the target animation value is reached, we can modify the
+ // visibility.
+ enabled: false
+ opacity: 0.0
+
+ onEnabledChanged: {
+ opacity = enabled ? 1.0 : 0.0
+ }
+
+ Behavior on opacity {
+ // Animate opacity.
+ NumberAnimation {
+ duration: hifi.effects.fadeInDuration
+ easing.type: Easing.OutCubic
+ }
+ }
+
+ onOpacityChanged: {
+ // Once we're transparent, disable the dialog's visibility.
+ visible = (opacity != 0.0)
+ }
+
+ onVisibleChanged: {
+ if (!visible) {
+ // Some dialogs should be destroyed when they become invisible.
+ if (destroyOnInvisible) {
+ destroy()
+ }
+ }
+ }
+
+
+ Keys.onPressed: {
+ switch(event.key) {
+ case Qt.Key_W:
+ if (event.modifiers == Qt.ControlModifier) {
+ enabled = false
+ event.accepted = true
+ }
+ break
+ }
+ }
+}
diff --git a/interface/resources/qml/controls/Dialog.qml b/interface/resources/qml/controls/VrDialog.qml
similarity index 100%
rename from interface/resources/qml/controls/Dialog.qml
rename to interface/resources/qml/controls/VrDialog.qml
diff --git a/interface/resources/qml/styles/HifiConstants.qml b/interface/resources/qml/styles/HifiConstants.qml
index fa556f2083..c232b993d1 100644
--- a/interface/resources/qml/styles/HifiConstants.qml
+++ b/interface/resources/qml/styles/HifiConstants.qml
@@ -13,10 +13,9 @@ Item {
readonly property color hifiBlue: "#0e7077"
readonly property color window: sysPalette.window
readonly property color dialogBackground: sysPalette.window
- //readonly property color dialogBackground: "#00000000"
readonly property color inputBackground: "white"
readonly property color background: sysPalette.dark
- readonly property color text: sysPalette.text
+ readonly property color text: "#202020"
readonly property color disabledText: "gray"
readonly property color hintText: "gray" // A bit darker than sysPalette.dark so that it is visible on the DK2
readonly property color light: sysPalette.light
diff --git a/interface/resources/sounds/short1.wav b/interface/resources/sounds/short1.wav
new file mode 100644
index 0000000000..fb03f5dd49
Binary files /dev/null and b/interface/resources/sounds/short1.wav differ
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 7effc93f07..449264fa0d 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -61,9 +61,14 @@
#include
#include
#include
+#include
#include
#include
#include
+#include
+#include
+#include
+#include
#include
#include
#include
@@ -102,7 +107,6 @@
#include "Util.h"
#include "InterfaceLogging.h"
-#include "GlWindow.h"
#include "avatar/AvatarManager.h"
#include "audio/AudioToolBox.h"
@@ -116,11 +120,7 @@
#include "devices/RealSense.h"
#include "devices/MIDIManager.h"
-#include "gpu/Batch.h"
-#include "gpu/GLBackend.h"
-
-#include
-
+#include "RenderDeferredTask.h"
#include "scripting/AccountScriptingInterface.h"
#include "scripting/AudioDeviceScriptingInterface.h"
#include "scripting/ClipboardScriptingInterface.h"
@@ -145,6 +145,7 @@
#include "ui/Stats.h"
#include "ui/AddressBarDialog.h"
+
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
#if defined(Q_OS_WIN)
extern "C" {
@@ -252,12 +253,12 @@ bool setupEssentials(int& argc, char** argv) {
}
// Set build version
QCoreApplication::setApplicationVersion(BUILD_VERSION);
-
+
DependencyManager::registerInheritance();
DependencyManager::registerInheritance();
Setting::init();
-
+
// Set dependencies
auto addressManager = DependencyManager::set();
auto nodeList = DependencyManager::set(NodeType::Agent, listenPort);
@@ -291,6 +292,7 @@ bool setupEssentials(int& argc, char** argv) {
auto discoverabilityManager = DependencyManager::set();
auto sceneScriptingInterface = DependencyManager::set();
auto offscreenUi = DependencyManager::set();
+ auto pathUtils = DependencyManager::set();
return true;
}
@@ -330,7 +332,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_enableProcessOctreeThread(true),
_octreeProcessor(),
_nodeBoundsDisplay(this),
- _applicationOverlay(),
_runningScriptsWidget(NULL),
_runningScriptsWidgetWasVisible(false),
_trayIcon(new QSystemTrayIcon(_window)),
@@ -341,7 +342,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_notifiedPacketVersionMismatchThisDomain(false),
_domainConnectionRefusals(QList()),
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
- _lastFaceTrackerUpdate(0)
+ _lastFaceTrackerUpdate(0),
+ _applicationOverlay()
{
_offscreenContext = new OffscreenGlCanvas();
setInstance(this);
@@ -355,9 +357,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf");
_window->setWindowTitle("Interface");
-
+
Model::setAbstractViewStateInterface(this); // The model class will sometimes need to know view state details from us
-
+
auto nodeList = DependencyManager::get();
_myAvatar = DependencyManager::get()->getMyAvatar();
@@ -369,7 +371,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_bookmarks = new Bookmarks(); // Before setting up the menu
_runningScriptsWidget = new RunningScriptsWidget(_window);
-
+ _renderEngine->addTask(render::TaskPointer(new RenderDeferredTask()));
+ _renderEngine->registerScene(_main3DScene);
+
// start the nodeThread so its event loop is running
QThread* nodeThread = new QThread(this);
nodeThread->setObjectName("Datagram Processor Thread");
@@ -377,14 +381,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// make sure the node thread is given highest priority
nodeThread->setPriority(QThread::TimeCriticalPriority);
-
+
_datagramProcessor = new DatagramProcessor(nodeList.data());
-
+
// have the NodeList use deleteLater from DM customDeleter
nodeList->setCustomDeleter([](Dependency* dependency) {
static_cast(dependency)->deleteLater();
});
-
+
// put the NodeList and datagram processing on the node thread
nodeList->moveToThread(nodeThread);
@@ -392,7 +396,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background
// downloads.
QSharedPointer geometryCacheP = DependencyManager::get();
- ResourceCache *geometryCache = geometryCacheP.data();
+ ResourceCache* geometryCache = geometryCacheP.data();
connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets);
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
@@ -401,20 +405,22 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// put the audio processing on a separate thread
QThread* audioThread = new QThread();
audioThread->setObjectName("Audio Thread");
-
+
auto audioIO = DependencyManager::get();
-
+
audioIO->setPositionGetter(getPositionForAudio);
audioIO->setOrientationGetter(getOrientationForAudio);
-
+
audioIO->moveToThread(audioThread);
connect(audioThread, &QThread::started, audioIO.data(), &AudioClient::start);
connect(audioIO.data(), &AudioClient::destroyed, audioThread, &QThread::quit);
connect(audioThread, &QThread::finished, audioThread, &QThread::deleteLater);
connect(audioIO.data(), &AudioClient::muteToggled, this, &Application::audioMuteToggled);
+ connect(audioIO.data(), &AudioClient::receivedFirstPacket,
+ &AudioScriptingInterface::getInstance(), &AudioScriptingInterface::receivedFirstPacket);
audioThread->start();
-
+
const DomainHandler& domainHandler = nodeList->getDomainHandler();
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
@@ -433,7 +439,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
auto discoverabilityManager = DependencyManager::get();
connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS);
-
+
// if we get a domain change, immediately attempt update location in metaverse server
connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain,
discoverabilityManager.data(), &DiscoverabilityManager::updateLocation);
@@ -467,14 +473,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// once the event loop has started, check and signal for an access token
QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
-
+
auto addressManager = DependencyManager::get();
-
+
// use our MyAvatar position and quat for address manager path
addressManager->setPositionGetter(getPositionForPath);
addressManager->setOrientationGetter(getOrientationForPath);
-
- connect(addressManager.data(), &AddressManager::rootPlaceNameChanged, this, &Application::updateWindowTitle);
+
+ connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle);
connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress);
#ifdef _WIN32
@@ -505,7 +511,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
cache->setMaximumCacheSize(MAXIMUM_CACHE_SIZE);
cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache");
networkAccessManager.setCache(cache);
-
+
ResourceCache::setRequestLimit(3);
_offscreenContext->create();
@@ -518,10 +524,16 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_window->setCentralWidget(container);
_window->restoreGeometry();
_window->setVisible(true);
+<<<<<<< HEAD
container->setFocus();
_offscreenContext->makeCurrent();
initializeGL();
// initialization continues in initializeGL when OpenGL context is ready
+=======
+ _glWidget->setFocusPolicy(Qt::StrongFocus);
+ _glWidget->setFocus();
+ _glWidget->setCursor(Qt::BlankCursor);
+>>>>>>> master
_menuBarHeight = Menu::getInstance()->height();
@@ -567,11 +579,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
connect(nodeList.data(), SIGNAL(dataReceived(const quint8, const int)),
bandwidthRecorder.data(), SLOT(updateInboundData(const quint8, const int)));
- connect(&_myAvatar->getSkeletonModel(), &SkeletonModel::skeletonLoaded,
+ connect(&_myAvatar->getSkeletonModel(), &SkeletonModel::skeletonLoaded,
this, &Application::checkSkeleton, Qt::QueuedConnection);
// Setup the userInputMapper with the actions
- // Setup the keyboardMouseDevice and the user input mapper with the default bindings
+ // Setup the keyboardMouseDevice and the user input mapper with the default bindings
_keyboardMouseDevice.registerToUserInputMapper(_userInputMapper);
_keyboardMouseDevice.assignDefaultInputMapping(_userInputMapper);
@@ -587,7 +599,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// do this as late as possible so that all required subsystems are initialized
loadScripts();
}
-
+
loadSettings();
int SAVE_SETTINGS_INTERVAL = 10 * MSECS_PER_SECOND; // Let's save every seconds for now
connect(&_settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
@@ -597,12 +609,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_settingsTimer.setSingleShot(false);
_settingsTimer.setInterval(SAVE_SETTINGS_INTERVAL);
_settingsThread.start();
-
+
_trayIcon->show();
-
+
// set the local loopback interface for local sounds from audio scripts
AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data());
-
+
#ifdef HAVE_RTMIDI
// setup the MIDIManager
MIDIManager& midiManagerInstance = MIDIManager::getInstance();
@@ -610,6 +622,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
#endif
this->installEventFilter(this);
+<<<<<<< HEAD
+=======
+ // The offscreen UI needs to intercept the mouse and keyboard
+ // events coming from the onscreen window
+ _glWidget->installEventFilter(DependencyManager::get().data());
+>>>>>>> master
// initialize our face trackers after loading the menu settings
auto faceshiftTracker = DependencyManager::get();
@@ -625,7 +643,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
void Application::aboutToQuit() {
emit beforeAboutToQuit();
-
+
_aboutToQuit = true;
cleanupBeforeQuit();
}
@@ -637,7 +655,7 @@ void Application::cleanupBeforeQuit() {
_datagramProcessor->shutdown(); // tell the datagram processor we're shutting down, so it can short circuit
_entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
ScriptEngine::stopAllScripts(this); // stop all currently running global scripts
-
+
// first stop all timers directly or by invokeMethod
// depending on what thread they run in
locationUpdateTimer->stop();
@@ -664,11 +682,11 @@ void Application::cleanupBeforeQuit() {
// let the avatar mixer know we're out
MyAvatar::sendKillAvatar();
-
+
// stop the AudioClient
QMetaObject::invokeMethod(DependencyManager::get().data(),
"stop", Qt::BlockingQueuedConnection);
-
+
// destroy the AudioClient so it and its thread have a chance to go down safely
DependencyManager::destroy();
@@ -677,12 +695,12 @@ void Application::cleanupBeforeQuit() {
#endif
}
-Application::~Application() {
+Application::~Application() {
EntityTree* tree = _entities.getTree();
tree->lockForWrite();
_entities.getTree()->setSimulation(NULL);
tree->unlock();
-
+
_octreeProcessor.terminate();
_entityEditSender.terminate();
@@ -693,7 +711,12 @@ Application::~Application() {
ModelEntityItem::cleanupLoadedAnimations();
+<<<<<<< HEAD
getActiveDisplayPlugin()->deactivate();
+=======
+ // stop the glWidget frame timer so it doesn't call paintGL
+ _glWidget->stopFrameTimer();
+>>>>>>> master
// remove avatars from physics engine
DependencyManager::get()->clearOtherAvatars();
@@ -706,10 +729,10 @@ Application::~Application() {
DependencyManager::destroy();
DependencyManager::destroy();
DependencyManager::destroy();
-
+
QThread* nodeThread = DependencyManager::get()->thread();
DependencyManager::destroy();
-
+
// ask the node thread to quit and wait until it is done
nodeThread->quit();
nodeThread->wait();
@@ -763,8 +786,8 @@ void Application::initializeGL() {
initDisplay();
qCDebug(interfaceapp, "Initialized Display.");
- // The UI can't be created until the primary OpenGL
- // context is created, because it needs to share
+ // The UI can't be created until the primary OpenGL
+ // context is created, because it needs to share
// texture resources
initializeUi();
qCDebug(interfaceapp, "Initialized Offscreen UI.");
@@ -839,8 +862,19 @@ void Application::paintGL() {
return;
}
PROFILE_RANGE(__FUNCTION__);
+<<<<<<< HEAD
auto displayPlugin = getActiveDisplayPlugin();
displayPlugin->preRender();
+=======
+ _glWidget->makeCurrent();
+
+ auto lodManager = DependencyManager::get();
+ gpu::Context context(new gpu::GLBackend());
+ RenderArgs renderArgs(&context, nullptr, getViewFrustum(), lodManager->getOctreeSizeScale(),
+ lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
+ RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
+
+>>>>>>> master
PerformanceTimer perfTimer("paintGL");
_offscreenContext->makeCurrent();
@@ -851,7 +885,7 @@ void Application::paintGL() {
{
PerformanceTimer perfTimer("renderOverlay");
- _applicationOverlay.renderOverlay();
+ _applicationOverlay.renderOverlay(&renderArgs);
}
glEnable(GL_LINE_SMOOTH);
@@ -901,11 +935,12 @@ void Application::paintGL() {
_myCamera.loadViewFrustum(_viewFrustum);
if (getShadowsEnabled()) {
- updateShadowMap();
+ renderArgs._renderMode = RenderArgs::SHADOW_RENDER_MODE;
+ updateShadowMap(&renderArgs);
}
+ renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
DependencyManager::get()->prepare();
-
// Primary rendering pass
auto primaryFbo = DependencyManager::get()->getPrimaryFramebuffer();
auto finalFbo = primaryFbo;
@@ -956,6 +991,26 @@ void Application::paintGL() {
}
glPopMatrix();
+#if 0
+ if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
+ _rearMirrorTools->render(&renderArgs, true, _glWidget->mapFromGlobal(QCursor::pos()));
+ } else if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
+ renderRearViewMirror(&renderArgs, _mirrorViewRect);
+ }
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(finalFbo));
+ glBlitFramebuffer(0, 0, _renderResolution.x, _renderResolution.y,
+ 0, 0, _glWidget->getDeviceSize().width(), _glWidget->getDeviceSize().height(),
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+
+ _applicationOverlay.displayOverlayTexture();
+ }
+if (!OculusManager::isConnected() || OculusManager::allowSwap()) {
+ _glWidget->swapBuffers();
+}
+#endif
// This might not be needed *right now*. We want to ensure that the FBO rendering
// has completed before we start trying to read from it in another context. However
@@ -975,6 +1030,7 @@ void Application::paintGL() {
Q_ASSERT(!QOpenGLContext::currentContext());
_offscreenContext->makeCurrent();
_frameCount++;
+ Stats::getInstance()->setRenderDetails(renderArgs._details);
}
void Application::runTests() {
@@ -1036,7 +1092,6 @@ void Application::resizeGL() {
int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
Stats::getInstance()->resetWidth(uiSize.x, horizontalOffset);
}
-
}
void Application::controlledBroadcastToNodes(const QByteArray& packet, const NodeSet& destinationNodeTypes) {
@@ -1102,11 +1157,11 @@ bool Application::event(QEvent* event) {
// handle custom URL
if (event->type() == QEvent::FileOpen) {
-
+
QFileOpenEvent* fileEvent = static_cast(event);
QUrl url = fileEvent->url();
-
+
if (!url.isEmpty()) {
QString urlString = url.toString();
if (canAcceptURL(urlString)) {
@@ -1115,7 +1170,7 @@ bool Application::event(QEvent* event) {
}
return false;
}
-
+
if (HFActionEvent::types().contains(event->type())) {
_controllerScriptingInterface.handleMetaEvent(static_cast(event));
}
@@ -1180,7 +1235,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
Menu::getInstance()->triggerOption(MenuOption::AddressBar);
} else if (isShifted) {
Menu::getInstance()->triggerOption(MenuOption::LodTools);
- }
+ }
break;
case Qt::Key_F: {
@@ -1221,7 +1276,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
case Qt::Key_Backslash:
Menu::getInstance()->triggerOption(MenuOption::Chat);
break;
-
+
case Qt::Key_Up:
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
if (!isShifted) {
@@ -1353,7 +1408,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
computePickRay(getTrueMouseX(), getTrueMouseY()));
sendEvent(this, &startActionEvent);
}
-
+
break;
}
case Qt::Key_Escape: {
@@ -1363,7 +1418,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
HFBackEvent startBackEvent(HFBackEvent::startType());
sendEvent(this, &startBackEvent);
}
-
+
break;
}
@@ -1420,7 +1475,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
void Application::focusOutEvent(QFocusEvent* event) {
_keyboardMouseDevice.focusOutEvent(event);
-
+
// synthesize events for keys currently pressed, since we may not get their release events
foreach (int key, _keysPressed) {
QKeyEvent event(QEvent::KeyRelease, key, Qt::NoModifier);
@@ -1454,7 +1509,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
#endif
_entities.mouseMoveEvent(event, deviceID);
-
+
_controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface.isMouseCaptured()) {
@@ -1462,7 +1517,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
}
_keyboardMouseDevice.mouseMoveEvent(event, deviceID);
-
+
}
void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
@@ -1487,7 +1542,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
if (event->button() == Qt::LeftButton) {
_mouseDragStarted = getTrueMousePosition();
_mousePressed = true;
-
+
if (mouseOnScreen()) {
if (DependencyManager::get()->mousePressEvent(getMouseX(), getMouseY())) {
// stop propagation
@@ -1504,7 +1559,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
return;
}
}
-
+
// nobody handled this - make it an action event on the _window object
HFActionEvent actionEvent(HFActionEvent::startType(),
computePickRay(event->x(), event->y()));
@@ -1552,14 +1607,14 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
if (event->button() == Qt::LeftButton) {
_mousePressed = false;
-
+
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && mouseOnScreen()) {
// let's set horizontal offset to give stats some margin to mirror
int horizontalOffset = MIRROR_VIEW_WIDTH;
Stats::getInstance()->checkClick(getMouseX(), getMouseY(),
getMouseDragStartedX(), getMouseDragStartedY(), horizontalOffset);
}
-
+
// fire an action end event
HFActionEvent actionEvent(HFActionEvent::endType(),
computePickRay(event->x(), event->y()));
@@ -1663,7 +1718,7 @@ void Application::dropEvent(QDropEvent *event) {
}
}
}
-
+
if (atLeastOneFileAccepted) {
event->acceptProposedAction();
}
@@ -1683,7 +1738,7 @@ void Application::dragEnterEvent(QDragEnterEvent* event) {
bool Application::acceptSnapshot(const QString& urlString) {
QUrl url(urlString);
QString snapshotPath = url.toLocalFile();
-
+
SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath);
if (snapshotData) {
if (!snapshotData->getURL().toString().isEmpty()) {
@@ -1693,7 +1748,7 @@ bool Application::acceptSnapshot(const QString& urlString) {
QMessageBox msgBox;
msgBox.setText("No location details were found in the file "
+ snapshotPath + ", try dragging in an authentic Hifi snapshot.");
-
+
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
}
@@ -1726,7 +1781,7 @@ void Application::checkFPS() {
void Application::idle() {
PerformanceTimer perfTimer("idle");
-
+
if (_aboutToQuit) {
return; // bail early, nothing to do here.
}
@@ -1856,16 +1911,14 @@ void Application::setEnableVRMode(bool enableVRMode) {
OculusManager::recalibrate();
} else {
OculusManager::abandonCalibration();
-
+
_mirrorCamera.setHmdPosition(glm::vec3());
_mirrorCamera.setHmdRotation(glm::quat());
_myCamera.setHmdPosition(glm::vec3());
_myCamera.setHmdRotation(glm::quat());
}
-
+
resizeGL();
-
- updateCursorVisibility();
}
#endif
@@ -1884,7 +1937,7 @@ ivec2 Application::getMouseDragStarted() const {
FaceTracker* Application::getActiveFaceTracker() {
auto faceshift = DependencyManager::get();
auto dde = DependencyManager::get();
-
+
return (dde->isActive() ? static_cast(dde.data()) :
(faceshift->isActive() ? static_cast(faceshift.data()) : NULL));
}
@@ -2017,14 +2070,14 @@ void Application::saveSettings() {
bool Application::importEntities(const QString& urlOrFilename) {
_entityClipboard.eraseAllOctreeElements();
-
+
QUrl url(urlOrFilename);
-
+
// if the URL appears to be invalid or relative, then it is probably a local file
if (!url.isValid() || url.isRelative()) {
url = QUrl::fromLocalFile(urlOrFilename);
}
-
+
bool success = _entityClipboard.readFromURL(url.toString());
if (success) {
_entityClipboard.reaverageOctreeElements();
@@ -2048,7 +2101,7 @@ void Application::initDisplay() {
void Application::init() {
// Make sure Login state is up to date
DependencyManager::get()->toggleLoginDialog();
-
+
_environment.init();
Q_ASSERT(_offscreenContext->getContext() == QOpenGLContext::currentContext());
@@ -2079,7 +2132,7 @@ void Application::init() {
_timerStart.start();
_lastTimeUpdated.start();
-
+
// when --url in command line, teleport to location
const QString HIFI_URL_COMMAND_LINE_KEY = "--url";
int urlIndex = arguments().indexOf(HIFI_URL_COMMAND_LINE_KEY);
@@ -2087,11 +2140,11 @@ void Application::init() {
if (urlIndex != -1) {
addressLookupString = arguments().value(urlIndex + 1);
}
-
+
DependencyManager::get()->loadSettings(addressLookupString);
-
+
qCDebug(interfaceapp) << "Loaded settings";
-
+
#ifdef __APPLE__
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseEnabled)) {
// on OS X we only setup sixense if the user wants it on - this allows running without the hid_init crash
@@ -2199,7 +2252,7 @@ void Application::updateMouseRay() {
PickRay pickRay = computePickRay(getTrueMouseX(), getTrueMouseY());
_mouseRayOrigin = pickRay.origin;
_mouseRayDirection = pickRay.direction;
-
+
// adjust for mirroring
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
glm::vec3 mouseRayOffset = _mouseRayOrigin - _viewFrustum.getPosition();
@@ -2233,28 +2286,27 @@ void Application::updateMyAvatarLookAtPosition() {
}
}
#endif
-
+
} else {
- AvatarSharedPointer lookingAt = _myAvatar->getLookAtTargetAvatar().toStrongRef();
- if (lookingAt && _myAvatar != lookingAt.data()) {
-
+ AvatarSharedPointer lookingAt = _myAvatar->getLookAtTargetAvatar().lock();
+ if (lookingAt && _myAvatar != lookingAt.get()) {
isLookingAtSomeone = true;
// If I am looking at someone else, look directly at one of their eyes
if (tracker && !tracker->isMuted()) {
// If a face tracker is active, look at the eye for the side my gaze is biased toward
if (tracker->getEstimatedEyeYaw() > _myAvatar->getHead()->getFinalYaw()) {
// Look at their right eye
- lookAtSpot = static_cast(lookingAt.data())->getHead()->getRightEyePosition();
+ lookAtSpot = static_cast(lookingAt.get())->getHead()->getRightEyePosition();
} else {
// Look at their left eye
- lookAtSpot = static_cast(lookingAt.data())->getHead()->getLeftEyePosition();
+ lookAtSpot = static_cast(lookingAt.get())->getHead()->getLeftEyePosition();
}
} else {
// Need to add randomly looking back and forth between left and right eye for case with no tracker
if (_myAvatar->isLookingAtLeftEye()) {
- lookAtSpot = static_cast(lookingAt.data())->getHead()->getLeftEyePosition();
+ lookAtSpot = static_cast(lookingAt.get())->getHead()->getLeftEyePosition();
} else {
- lookAtSpot = static_cast(lookingAt.data())->getHead()->getRightEyePosition();
+ lookAtSpot = static_cast(lookingAt.get())->getHead()->getRightEyePosition();
}
}
} else {
@@ -2324,7 +2376,7 @@ void Application::updateDialogs(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateDialogs()");
auto dialogsManager = DependencyManager::get();
-
+
// Update bandwidth dialog, if any
BandwidthDialog* bandwidthDialog = dialogsManager->getBandwidthDialog();
if (bandwidthDialog) {
@@ -2347,17 +2399,8 @@ void Application::updateCursor(float deltaTime) {
lastMousePos = QCursor::pos();
}
-void Application::updateCursorVisibility() {
- if (!_cursorVisible || getActiveDisplayPlugin()->isStereo()) {
- _window->setCursor(Qt::BlankCursor);
- } else {
- _window->unsetCursor();
- }
-}
-
void Application::setCursorVisible(bool visible) {
_cursorVisible = visible;
- updateCursorVisibility();
}
void Application::update(float deltaTime) {
@@ -2528,7 +2571,7 @@ void Application::update(float deltaTime) {
}
}
- // send packet containing downstream audio stats to the AudioMixer
+ // send packet containing downstream audio stats to the AudioMixer
{
quint64 sinceLastNack = now - _lastSendDownstreamAudioStats;
if (sinceLastNack > TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS) {
@@ -2550,64 +2593,64 @@ int Application::sendNackPackets() {
// iterates thru all nodes in NodeList
auto nodeList = DependencyManager::get();
-
+
nodeList->eachNode([&](const SharedNodePointer& node){
-
+
if (node->getActiveSocket() && node->getType() == NodeType::EntityServer) {
-
+
QUuid nodeUUID = node->getUUID();
-
+
// if there are octree packets from this node that are waiting to be processed,
// don't send a NACK since the missing packets may be among those waiting packets.
if (_octreeProcessor.hasPacketsToProcessFrom(nodeUUID)) {
return;
}
-
+
_octreeSceneStatsLock.lockForRead();
-
+
// retreive octree scene stats of this node
if (_octreeServerSceneStats.find(nodeUUID) == _octreeServerSceneStats.end()) {
_octreeSceneStatsLock.unlock();
return;
}
-
+
// get sequence number stats of node, prune its missing set, and make a copy of the missing set
SequenceNumberStats& sequenceNumberStats = _octreeServerSceneStats[nodeUUID].getIncomingOctreeSequenceNumberStats();
sequenceNumberStats.pruneMissingSet();
const QSet missingSequenceNumbers = sequenceNumberStats.getMissingSet();
-
+
_octreeSceneStatsLock.unlock();
-
+
// construct nack packet(s) for this node
int numSequenceNumbersAvailable = missingSequenceNumbers.size();
QSet::const_iterator missingSequenceNumbersIterator = missingSequenceNumbers.constBegin();
while (numSequenceNumbersAvailable > 0) {
-
+
char* dataAt = packet;
int bytesRemaining = MAX_PACKET_SIZE;
-
+
// pack header
int numBytesPacketHeader = nodeList->populatePacketHeader(packet, PacketTypeOctreeDataNack);
dataAt += numBytesPacketHeader;
bytesRemaining -= numBytesPacketHeader;
-
+
// calculate and pack the number of sequence numbers
int numSequenceNumbersRoomFor = (bytesRemaining - sizeof(uint16_t)) / sizeof(OCTREE_PACKET_SEQUENCE);
uint16_t numSequenceNumbers = min(numSequenceNumbersAvailable, numSequenceNumbersRoomFor);
uint16_t* numSequenceNumbersAt = (uint16_t*)dataAt;
*numSequenceNumbersAt = numSequenceNumbers;
dataAt += sizeof(uint16_t);
-
+
// pack sequence numbers
for (int i = 0; i < numSequenceNumbers; i++) {
OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt;
*sequenceNumberAt = *missingSequenceNumbersIterator;
dataAt += sizeof(OCTREE_PACKET_SEQUENCE);
-
+
missingSequenceNumbersIterator++;
}
numSequenceNumbersAvailable -= numSequenceNumbers;
-
+
// send it
nodeList->writeUnverifiedDatagram(packet, dataAt - packet, node);
packetsSent++;
@@ -2649,7 +2692,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
int unknownJurisdictionServers = 0;
auto nodeList = DependencyManager::get();
-
+
nodeList->eachNode([&](const SharedNodePointer& node) {
// only send to the NodeTypes that are serverType
if (node->getActiveSocket() && node->getType() == serverType) {
@@ -2709,17 +2752,17 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
if (wantExtraDebugging) {
qCDebug(interfaceapp, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer);
}
-
+
nodeList->eachNode([&](const SharedNodePointer& node){
// only send to the NodeTypes that are serverType
if (node->getActiveSocket() && node->getType() == serverType) {
-
+
// get the server bounds for this server
QUuid nodeUUID = node->getUUID();
-
+
bool inView = false;
bool unknownView = false;
-
+
// if we haven't heard from this voxel server, go ahead and send it a query, so we
// can get the jurisdiction...
if (jurisdictions.find(nodeUUID) == jurisdictions.end()) {
@@ -2729,9 +2772,9 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
}
} else {
const JurisdictionMap& map = (jurisdictions)[nodeUUID];
-
+
unsigned char* rootCode = map.getRootOctalCode();
-
+
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
@@ -2741,7 +2784,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
rootDetails.s * TREE_SCALE);
-
+
ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
inView = true;
@@ -2754,7 +2797,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
}
}
}
-
+
if (inView) {
_octreeQuery.setMaxQueryPacketsPerSecond(perServerPPS);
} else if (unknownView) {
@@ -2762,7 +2805,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
qCDebug(interfaceapp) << "no known jurisdiction for node " << *node << ", give it budget of "
<< perUnknownServer << " to send us jurisdiction.";
}
-
+
// set the query's position/orientation to be degenerate in a manner that will get the scene quickly
// If there's only one server, then don't do this, and just let the normal voxel query pass through
// as expected... this way, we will actually get a valid scene if there is one to be seen
@@ -2789,12 +2832,12 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
// insert packet type/version and node UUID
endOfQueryPacket += nodeList->populatePacketHeader(reinterpret_cast(endOfQueryPacket), packetType);
-
+
// encode the query data...
endOfQueryPacket += _octreeQuery.getBroadcastData(endOfQueryPacket);
-
+
int packetLength = endOfQueryPacket - queryPacket;
-
+
// make sure we still have an active socket
nodeList->writeUnverifiedDatagram(reinterpret_cast(queryPacket), packetLength, node);
}
@@ -2808,6 +2851,7 @@ bool Application::isHMDMode() const {
QRect Application::getDesirableApplicationGeometry() {
QRect applicationGeometry = getWindow()->geometry();
#if 0
+
// If our parent window is on the HMD, then don't use its geometry, instead use
// the "main screen" geometry.
HMDToolsDialog* hmdTools = DependencyManager::get()->getHMDToolsDialog();
@@ -2838,7 +2882,7 @@ glm::vec3 Application::getSunDirection() {
// FIXME, preprocessor guard this check to occur only in DEBUG builds
static QThread * activeRenderingThread = nullptr;
-void Application::updateShadowMap() {
+void Application::updateShadowMap(RenderArgs* renderArgs) {
activeRenderingThread = QThread::currentThread();
PerformanceTimer perfTimer("shadowMap");
@@ -2851,14 +2895,14 @@ void Application::updateShadowMap() {
glm::vec3 lightDirection = getSunDirection();
glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection);
glm::quat inverseRotation = glm::inverse(rotation);
-
+
const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f };
const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f),
glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) };
-
+
float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip());
_myCamera.loadViewFrustum(_viewFrustum);
-
+
int matrixCount = 1;
//int targetSize = fbo->width();
int sourceSize = shadowFramebuffer->getWidth();
@@ -2900,12 +2944,12 @@ void Application::updateShadowMap() {
_shadowDistances[i] = -glm::distance(_viewFrustum.getPosition(), center) - radius * RADIUS_SCALE;
}
center = inverseRotation * center;
-
+
// to reduce texture "shimmer," move in texel increments
float texelSize = (2.0f * radius) / targetSize;
center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize,
roundf(center.z / texelSize) * texelSize);
-
+
glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius);
glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius);
@@ -2947,25 +2991,9 @@ void Application::updateShadowMap() {
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
- {
- PerformanceTimer perfTimer("avatarManager");
- DependencyManager::get()->renderAvatars(RenderArgs::SHADOW_RENDER_MODE);
- }
-
{
PerformanceTimer perfTimer("entities");
- _entities.render(RenderArgs::SHADOW_RENDER_MODE);
- }
-
- // render JS/scriptable overlays
- {
- PerformanceTimer perfTimer("3dOverlays");
- _overlays.renderWorld(false, RenderArgs::SHADOW_RENDER_MODE);
- }
-
- {
- PerformanceTimer perfTimer("3dOverlaysFront");
- _overlays.renderWorld(true, RenderArgs::SHADOW_RENDER_MODE);
+ _entities.render(renderArgs);
}
glDisable(GL_POLYGON_OFFSET_FILL);
@@ -2977,7 +3005,8 @@ void Application::updateShadowMap() {
glMatrixMode(GL_MODELVIEW);
}
-
+
+ glViewport(0, 0, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
activeRenderingThread = nullptr;
}
@@ -3008,11 +3037,11 @@ bool Application::shouldRenderMesh(float largestDimension, float distanceToCamer
return DependencyManager::get()->shouldRenderMesh(largestDimension, distanceToCamera);
}
-float Application::getSizeScale() const {
+float Application::getSizeScale() const {
return DependencyManager::get()->getOctreeSizeScale();
}
-int Application::getBoundaryLevelAdjust() const {
+int Application::getBoundaryLevelAdjust() const {
return DependencyManager::get()->getBoundaryLevelAdjust();
}
@@ -3033,22 +3062,22 @@ PickRay Application::computePickRay(float x, float y) const {
return result;
}
-QImage Application::renderAvatarBillboard() {
+QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) {
auto primaryFramebuffer = DependencyManager::get()->getPrimaryFramebuffer();
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFramebuffer));
-
+
// clear the alpha channel so the background is transparent
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
-
+
// the "glow" here causes an alpha of one
- Glower glower;
-
+ Glower glower(renderArgs);
+
const int BILLBOARD_SIZE = 64;
#if 0
- renderRearViewMirror(QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,
+ renderRearViewMirror(renderArgs, QRect(0, _glWidget->getDeviceHeight() - BILLBOARD_SIZE,
BILLBOARD_SIZE, BILLBOARD_SIZE),
true);
#endif
@@ -3056,9 +3085,9 @@ QImage Application::renderAvatarBillboard() {
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-
+
glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
+
return image;
}
@@ -3102,7 +3131,143 @@ const ViewFrustum* Application::getDisplayViewFrustum() const {
return &_displayViewFrustum;
}
-void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
+// WorldBox Render Data & rendering functions
+
+class WorldBoxRenderData {
+public:
+ typedef render::Payload Payload;
+ typedef Payload::DataPointer Pointer;
+
+ int _val = 0;
+ static render::ItemID _item; // unique WorldBoxRenderData
+};
+
+render::ItemID WorldBoxRenderData::_item = 0;
+
+namespace render {
+ template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
+ template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
+ template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
+ if (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
+ PerformanceTimer perfTimer("worldBox");
+
+ auto& batch = *args->_batch;
+ DependencyManager::get()->bindSimpleProgram(batch);
+ renderWorldBox(batch);
+ }
+ }
+}
+
+// Background Render Data & rendering functions
+class BackgroundRenderData {
+public:
+ typedef render::Payload Payload;
+ typedef Payload::DataPointer Pointer;
+
+ Stars _stars;
+ Environment* _environment;
+
+ BackgroundRenderData(Environment* environment) : _environment(environment) {
+ }
+
+ static render::ItemID _item; // unique WorldBoxRenderData
+};
+
+render::ItemID BackgroundRenderData::_item = 0;
+
+namespace render {
+ template <> const ItemKey payloadGetKey(const BackgroundRenderData::Pointer& stuff) { return ItemKey::Builder::background(); }
+ template <> const Item::Bound payloadGetBound(const BackgroundRenderData::Pointer& stuff) { return Item::Bound(); }
+ template <> void payloadRender(const BackgroundRenderData::Pointer& background, RenderArgs* args) {
+
+ // Background rendering decision
+ auto skyStage = DependencyManager::get()->getSkyStage();
+ auto skybox = model::SkyboxPointer();
+ if (skyStage->getBackgroundMode() == model::SunSkyStage::NO_BACKGROUND) {
+ } else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_DOME) {
+ if (/*!selfAvatarOnly &&*/ Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
+ PerformanceTimer perfTimer("stars");
+ PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
+ "Application::payloadRender() ... stars...");
+ if (!background->_stars.isStarsLoaded()) {
+ background->_stars.generate(STARFIELD_NUM_STARS, STARFIELD_SEED);
+ }
+ // should be the first rendering pass - w/o depth buffer / lighting
+
+ // compute starfield alpha based on distance from atmosphere
+ float alpha = 1.0f;
+ bool hasStars = true;
+
+ if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
+ // TODO: handle this correctly for zones
+ const EnvironmentData& closestData = background->_environment->getClosestData(args->_viewFrustum->getPosition()); // was theCamera instead of _viewFrustum
+
+ if (closestData.getHasStars()) {
+ const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f;
+ const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f;
+
+ glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation())
+ / closestData.getAtmosphereOuterRadius();
+ float height = glm::distance(args->_viewFrustum->getPosition()/*theCamera.getPosition()*/, closestData.getAtmosphereCenter());
+ if (height < closestData.getAtmosphereInnerRadius()) {
+ // If we're inside the atmosphere, then determine if our keyLight is below the horizon
+ alpha = 0.0f;
+
+ if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
+ float directionY = glm::clamp(sunDirection.y,
+ -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
+ + APPROXIMATE_DISTANCE_FROM_HORIZON;
+ alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
+ }
+
+
+ } else if (height < closestData.getAtmosphereOuterRadius()) {
+ alpha = (height - closestData.getAtmosphereInnerRadius()) /
+ (closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius());
+
+ if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
+ float directionY = glm::clamp(sunDirection.y,
+ -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
+ + APPROXIMATE_DISTANCE_FROM_HORIZON;
+ alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
+ }
+ }
+ } else {
+ hasStars = false;
+ }
+ }
+
+ // finally render the starfield
+ if (hasStars) {
+ background->_stars.render(args->_viewFrustum->getFieldOfView(), args->_viewFrustum->getAspectRatio(), args->_viewFrustum->getNearClip(), alpha);
+ }
+
+ // draw the sky dome
+ if (/*!selfAvatarOnly &&*/ Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
+ PerformanceTimer perfTimer("atmosphere");
+ PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
+ "Application::displaySide() ... atmosphere...");
+ background->_environment->renderAtmospheres(*(args->_viewFrustum));
+ }
+
+ }
+ } else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_BOX) {
+ PerformanceTimer perfTimer("skybox");
+
+ skybox = skyStage->getSkybox();
+ if (skybox) {
+ gpu::Batch batch;
+ model::Skybox::render(batch, *(Application::getInstance()->getDisplayViewFrustum()), *skybox);
+
+ gpu::GLBackend::renderBatch(batch, true);
+ glUseProgram(0);
+ }
+ }
+ }
+}
+
+
+void Application::displaySide(RenderArgs* renderArgs, const Camera& theCamera, bool selfAvatarOnly) {
activeRenderingThread = QThread::currentThread();
PROFILE_RANGE(__FUNCTION__);
PerformanceTimer perfTimer("display");
@@ -3138,6 +3303,7 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
if (theCamera.getMode() == CAMERA_MODE_MIRROR) {
viewTransform.setScale(Transform::Vec3(-1.0f, 1.0f, 1.0f));
}
+
setViewTransform(viewTransform);
// Setup 3D lights (after the camera transform, so that they are positioned in world space)
@@ -3160,86 +3326,17 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][2]);
}
+ // The pending changes collecting the changes here
+ render::PendingChanges pendingChanges;
+
// Background rendering decision
- auto skyStage = DependencyManager::get()->getSkyStage();
- auto skybox = model::SkyboxPointer();
- if (skyStage->getBackgroundMode() == model::SunSkyStage::NO_BACKGROUND) {
- } else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_DOME) {
- if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
- PerformanceTimer perfTimer("stars");
- PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
- "Application::displaySide() ... stars...");
- if (!_stars.isStarsLoaded()) {
- _stars.generate(STARFIELD_NUM_STARS, STARFIELD_SEED);
- }
- // should be the first rendering pass - w/o depth buffer / lighting
+ if (BackgroundRenderData::_item == 0) {
+ auto backgroundRenderData = BackgroundRenderData::Pointer(new BackgroundRenderData(&_environment));
+ auto backgroundRenderPayload = render::PayloadPointer(new BackgroundRenderData::Payload(backgroundRenderData));
+ BackgroundRenderData::_item = _main3DScene->allocateID();
+ pendingChanges.resetItem(WorldBoxRenderData::_item, backgroundRenderPayload);
+ } else {
- // compute starfield alpha based on distance from atmosphere
- float alpha = 1.0f;
- bool hasStars = true;
-
- if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
- // TODO: handle this correctly for zones
- const EnvironmentData& closestData = _environment.getClosestData(_displayViewFrustum.getPosition());
-
- if (closestData.getHasStars()) {
- const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f;
- const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f;
-
- glm::vec3 sunDirection = (getAvatarPosition() - closestData.getSunLocation())
- / closestData.getAtmosphereOuterRadius();
- float height = glm::distance(_displayViewFrustum.getPosition(), closestData.getAtmosphereCenter());
- if (height < closestData.getAtmosphereInnerRadius()) {
- // If we're inside the atmosphere, then determine if our keyLight is below the horizon
- alpha = 0.0f;
-
- if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
- float directionY = glm::clamp(sunDirection.y,
- -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
- + APPROXIMATE_DISTANCE_FROM_HORIZON;
- alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
- }
-
-
- } else if (height < closestData.getAtmosphereOuterRadius()) {
- alpha = (height - closestData.getAtmosphereInnerRadius()) /
- (closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius());
-
- if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
- float directionY = glm::clamp(sunDirection.y,
- -APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
- + APPROXIMATE_DISTANCE_FROM_HORIZON;
- alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
- }
- }
- } else {
- hasStars = false;
- }
- }
-
- // finally render the starfield
- if (hasStars) {
- _stars.render(_displayViewFrustum.getFieldOfView(), _displayViewFrustum.getAspectRatio(), _displayViewFrustum.getNearClip(), alpha);
- }
-
- // draw the sky dome
- if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
- PerformanceTimer perfTimer("atmosphere");
- PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
- "Application::displaySide() ... atmosphere...");
- _environment.renderAtmospheres(_displayViewFrustum.getPosition());
- }
-
- }
- } else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_BOX) {
- skybox = skyStage->getSkybox();
- if (skybox) {
- gpu::Batch batch;
- model::Skybox::render(batch, _displayViewFrustum, *skybox);
-
- gpu::GLBackend::renderBatch(batch);
- glUseProgram(0);
- }
}
if (Menu::getInstance()->isOptionChecked(MenuOption::Wireframe)) {
@@ -3249,13 +3346,10 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
- DependencyManager::get()->prepare();
+ // Assuming nothing get's rendered through that
if (!selfAvatarOnly) {
- // draw a red sphere
- float originSphereRadius = 0.05f;
- DependencyManager::get()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
-
+
// render models...
if (DependencyManager::get()->shouldRenderEntities()) {
PerformanceTimer perfTimer("entities");
@@ -3275,18 +3369,9 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
if (theCamera.getMode() == CAMERA_MODE_MIRROR) {
renderMode = RenderArgs::MIRROR_RENDER_MODE;
}
- _entities.render(renderMode, RenderArgs::MONO, renderDebugFlags);
-
- if (!Menu::getInstance()->isOptionChecked(MenuOption::Wireframe)) {
- // Restaure polygon mode
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- }
- }
-
- // render JS/scriptable overlays
- {
- PerformanceTimer perfTimer("3dOverlays");
- _overlays.renderWorld(false);
+ renderArgs->_renderMode = renderMode;
+ renderArgs->_debugFlags = renderDebugFlags;
+ _entities.render(renderArgs);
}
// render the ambient occlusion effect if enabled
@@ -3297,13 +3382,21 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
DependencyManager::get()->render();
}
}
-
- bool mirrorMode = (theCamera.getMode() == CAMERA_MODE_MIRROR);
- {
- PerformanceTimer perfTimer("avatars");
- DependencyManager::get()->renderAvatars(mirrorMode ? RenderArgs::MIRROR_RENDER_MODE : RenderArgs::NORMAL_RENDER_MODE,
- false, selfAvatarOnly);
+ // Make sure the WorldBox is in the scene
+ if (WorldBoxRenderData::_item == 0) {
+ auto worldBoxRenderData = WorldBoxRenderData::Pointer(new WorldBoxRenderData());
+ auto worldBoxRenderPayload = render::PayloadPointer(new WorldBoxRenderData::Payload(worldBoxRenderData));
+
+ WorldBoxRenderData::_item = _main3DScene->allocateID();
+
+ pendingChanges.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
+ } else {
+
+ pendingChanges.updateItem(WorldBoxRenderData::_item,
+ [](WorldBoxRenderData& payload) {
+ payload._val++;
+ });
}
if (true) {
@@ -3312,20 +3405,55 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
auto skyStage = DependencyManager::get()->getSkyStage();
DependencyManager::get()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity(), skyStage->getSunLight()->getAmbientIntensity());
DependencyManager::get()->setGlobalAtmosphere(skyStage->getAtmosphere());
- DependencyManager::get()->setGlobalSkybox(skybox);
- PROFILE_RANGE("DeferredLighting");
- PerformanceTimer perfTimer("lighting");
- Q_ASSERT(_offscreenContext->getContext() == QOpenGLContext::currentContext());
- DependencyManager::get()->render();
+ auto skybox = model::SkyboxPointer();
+ if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_BOX) {
+ skybox = skyStage->getSkybox();
+ }
+ DependencyManager::get()->setGlobalSkybox(skybox);
}
{
- PerformanceTimer perfTimer("avatarsPostLighting");
- DependencyManager::get()->renderAvatars(mirrorMode ? RenderArgs::MIRROR_RENDER_MODE : RenderArgs::NORMAL_RENDER_MODE,
- true, selfAvatarOnly);
+ PerformanceTimer perfTimer("SceneProcessPendingChanges");
+ _main3DScene->enqueuePendingChanges(pendingChanges);
+
+ _main3DScene->processPendingChangesQueue();
+ }
+
+ // For now every frame pass the renderContext
+ {
+ PerformanceTimer perfTimer("EngineRun");
+ render::RenderContext renderContext;
+
+ auto sceneInterface = DependencyManager::get();
+
+ renderContext._cullOpaque = sceneInterface->doEngineCullOpaque();
+ renderContext._sortOpaque = sceneInterface->doEngineSortOpaque();
+ renderContext._renderOpaque = sceneInterface->doEngineRenderOpaque();
+ renderContext._cullTransparent = sceneInterface->doEngineCullTransparent();
+ renderContext._sortTransparent = sceneInterface->doEngineSortTransparent();
+ renderContext._renderTransparent = sceneInterface->doEngineRenderTransparent();
+
+ renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems();
+ renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems();
+
+ renderArgs->_shouldRender = LODManager::shouldRender;
+
+ renderContext.args = renderArgs;
+ renderArgs->_viewFrustum = getDisplayViewFrustum();
+ _renderEngine->setRenderContext(renderContext);
+
+ // Before the deferred pass, let's try to use the render engine
+ _renderEngine->run();
+
+ auto engineRC = _renderEngine->getRenderContext();
+ sceneInterface->setEngineFeedOpaqueItems(engineRC->_numFeedOpaqueItems);
+ sceneInterface->setEngineDrawnOpaqueItems(engineRC->_numDrawnOpaqueItems);
+
+ sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems);
+ sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems);
+
}
-
//Render the sixense lasers
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
_myAvatar->renderLaserPointers();
@@ -3333,12 +3461,6 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
if (!selfAvatarOnly) {
_nodeBoundsDisplay.draw();
-
- // Render the world box
- if (!mirrorMode && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
- PerformanceTimer perfTimer("worldBox");
- renderWorldBox();
- }
// render octree fades if they exist
if (_octreeFades.size() > 0) {
@@ -3347,7 +3469,7 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
"Application::displaySide() ... octree fades...");
_octreeFadesLock.lockForWrite();
for(std::vector::iterator fade = _octreeFades.begin(); fade != _octreeFades.end();) {
- fade->render();
+ fade->render(renderArgs);
if(fade->isDone()) {
fade = _octreeFades.erase(fade);
} else {
@@ -3368,14 +3490,6 @@ void Application::displaySide(const Camera& theCamera, bool selfAvatarOnly) {
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
- // Render 3D overlays that should be drawn in front
- {
- PerformanceTimer perfTimer("3dOverlaysFront");
- glClear(GL_DEPTH_BUFFER_BIT);
- Glower glower; // Sets alpha to 1.0
- _overlays.renderWorld(true);
- }
-
activeRenderingThread = nullptr;
}
@@ -3413,11 +3527,37 @@ bool Application::getShadowsEnabled() {
menubar->isOptionChecked(MenuOption::CascadedShadows);
}
-bool Application::getCascadeShadowsEnabled() {
- return Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows);
+bool Application::getCascadeShadowsEnabled() {
+ return Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows);
}
-void Application::renderRearViewMirror(const QRect& region, bool billboard) {
+glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
+ float horizontalScale = _glWidget->getDeviceWidth() / 2.0f;
+ float verticalScale = _glWidget->getDeviceHeight() / 2.0f;
+
+ // -1,-1 is 0,windowHeight
+ // 1,1 is windowWidth,0
+
+ // -1,1 1,1
+ // +-----------------------+
+ // | | |
+ // | | |
+ // | -1,0 | |
+ // |-----------+-----------|
+ // | 0,0 |
+ // | | |
+ // | | |
+ // | | |
+ // +-----------------------+
+ // -1,-1 1,-1
+
+ glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale,
+ ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->getDeviceHeight());
+
+ return screenPoint;
+}
+
+void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool billboard) {
// Grab current viewport to reset it at the end
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
@@ -3435,22 +3575,22 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
_myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
} else { // HEAD zoom level
- // FIXME note that the positioing of the camera relative to the avatar can suffer limited
- // precision as the user's position moves further away from the origin. Thus at
- // /1e7,1e7,1e7 (well outside the buildable volume) the mirror camera veers and sways
- // wildly as you rotate your avatar because the floating point values are becoming
- // larger, squeezing out the available digits of precision you have available at the
- // human scale for camera positioning.
+ // FIXME note that the positioing of the camera relative to the avatar can suffer limited
+ // precision as the user's position moves further away from the origin. Thus at
+ // /1e7,1e7,1e7 (well outside the buildable volume) the mirror camera veers and sways
+ // wildly as you rotate your avatar because the floating point values are becoming
+ // larger, squeezing out the available digits of precision you have available at the
+ // human scale for camera positioning.
- // Previously there was a hack to correct this using the mechanism of repositioning
- // the avatar at the origin of the world for the purposes of rendering the mirror,
- // but it resulted in failing to render the avatar's head model in the mirror view
- // when in first person mode. Presumably this was because of some missed culling logic
- // that was not accounted for in the hack.
+ // Previously there was a hack to correct this using the mechanism of repositioning
+ // the avatar at the origin of the world for the purposes of rendering the mirror,
+ // but it resulted in failing to render the avatar's head model in the mirror view
+ // when in first person mode. Presumably this was because of some missed culling logic
+ // that was not accounted for in the hack.
- // This was removed in commit 71e59cfa88c6563749594e25494102fe01db38e9 but could be further
+ // This was removed in commit 71e59cfa88c6563749594e25494102fe01db38e9 but could be further
// investigated in order to adapt the technique while fixing the head rendering issue,
- // but the complexity of the hack suggests that a better approach
+ // but the complexity of the hack suggests that a better approach
_mirrorCamera.setPosition(_myAvatar->getHead()->getEyePosition() +
_myAvatar->getOrientation() * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
}
@@ -3461,7 +3601,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
if (billboard) {
QSize size = DependencyManager::get()->getFrameBufferSize();
glViewport(region.x(), size.height() - region.y() - region.height(), region.width(), region.height());
- glScissor(region.x(), size.height() - region.y() - region.height(), region.width(), region.height());
+ glScissor(region.x(), size.height() - region.y() - region.height(), region.width(), region.height());
} else {
// if not rendering the billboard, the region is in device independent coordinates; must convert to device
QSize size = DependencyManager::get()->getFrameBufferSize();
@@ -3475,12 +3615,11 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
// render rear mirror view
glPushMatrix();
- displaySide(_mirrorCamera, true);
+ displaySide(renderArgs, _mirrorCamera, true, billboard);
glPopMatrix();
if (!billboard) {
- glm::vec2 mpos = getActiveDisplayPlugin()->getUiMousePosition();
- _rearMirrorTools->render(false, QPoint(mpos.x, mpos.y));
+ _rearMirrorTools->render(renderArgs, false, _glWidget->mapFromGlobal(QCursor::pos()));
}
// reset Viewport and projection matrix
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
@@ -3500,6 +3639,7 @@ void Application::resetSensors() {
QPoint windowCenter = mainWindow->geometry().center();
_glWidget->cursor().setPos(currentScreen, windowCenter);
#endif
+
_myAvatar->reset();
QMetaObject::invokeMethod(DependencyManager::get().data(), "reset", Qt::QueuedConnection);
@@ -3531,12 +3671,12 @@ void Application::updateWindowTitle(){
QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) ";
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
- QString currentPlaceName = DependencyManager::get()->getRootPlaceName();
-
+ QString currentPlaceName = DependencyManager::get()->getHost();
+
if (currentPlaceName.isEmpty()) {
currentPlaceName = nodeList->getDomainHandler().getHostname();
}
-
+
QString title = QString() + (!username.isEmpty() ? username + " @ " : QString())
+ currentPlaceName + connectionStatus + buildVersion;
@@ -3550,7 +3690,6 @@ void Application::updateWindowTitle(){
void Application::clearDomainOctreeDetails() {
qCDebug(interfaceapp) << "Clearing domain octree details...";
// reset the environment so that we don't erroneously end up with multiple
- _environment.resetToDefault();
// reset our node to stats and node to jurisdiction maps... since these must be changing...
_entityServerJurisdictions.lockForWrite();
@@ -3582,7 +3721,7 @@ void Application::domainConnectionDenied(const QString& reason) {
void Application::connectedToDomain(const QString& hostname) {
AccountManager& accountManager = AccountManager::getInstance();
const QUuid& domainID = DependencyManager::get()->getDomainHandler().getUUID();
-
+
if (accountManager.isLoggedIn() && !domainID.isNull()) {
_notifiedPacketVersionMismatchThisDomain = false;
}
@@ -3766,7 +3905,7 @@ void Application::saveScripts() {
Settings settings;
settings.beginWriteArray(SETTINGS_KEY);
settings.remove("");
-
+
QStringList runningScripts = getRunningScripts();
int i = 0;
for (auto it = runningScripts.begin(); it != runningScripts.end(); ++it) {
@@ -3817,7 +3956,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("Overlays", &_overlays);
qScriptRegisterMetaType(scriptEngine, OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue);
- qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue,
+ qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue,
RayToOverlayIntersectionResultFromScriptValue);
QScriptValue windowValue = scriptEngine->registerGlobalObject("Window", DependencyManager::get().data());
@@ -3828,7 +3967,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
LocationScriptingInterface::locationSetter);
scriptEngine->registerFunction("WebWindow", WebWindowClass::constructor, 1);
-
+
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
@@ -3840,7 +3979,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
qScriptRegisterMetaType(scriptEngine, DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
scriptEngine->registerGlobalObject("AvatarManager", DependencyManager::get().data());
-
+
scriptEngine->registerGlobalObject("Joysticks", &JoystickScriptingInterface::getInstance());
qScriptRegisterMetaType(scriptEngine, joystickToScriptValue, joystickFromScriptValue);
@@ -3848,6 +3987,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("LODManager", DependencyManager::get().data());
+ scriptEngine->registerGlobalObject("Paths", DependencyManager::get().data());
+
QScriptValue hmdInterface = scriptEngine->registerGlobalObject("HMD", &HMDScriptingInterface::getInstance());
scriptEngine->registerFunction(hmdInterface, "getHUDLookAtPosition2D", HMDScriptingInterface::getHUDLookAtPosition2D, 0);
scriptEngine->registerFunction(hmdInterface, "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0);
@@ -3895,7 +4036,7 @@ void Application::initializeAcceptedFiles() {
bool Application::canAcceptURL(const QString& urlString) {
initializeAcceptedFiles();
-
+
QUrl url(urlString);
if (urlString.startsWith(HIFI_URL_SCHEME)) {
return true;
@@ -3913,7 +4054,7 @@ bool Application::canAcceptURL(const QString& urlString) {
bool Application::acceptURL(const QString& urlString) {
initializeAcceptedFiles();
-
+
if (urlString.startsWith(HIFI_URL_SCHEME)) {
// this is a hifi URL - have the AddressManager handle it
QMetaObject::invokeMethod(DependencyManager::get().data(), "handleLookupString",
@@ -3951,19 +4092,19 @@ bool Application::askToSetAvatarUrl(const QString& url) {
msgBox.exec();
return false;
}
-
+
// Download the FST file, to attempt to determine its model type
QVariantHash fstMapping = FSTReader::downloadMapping(url);
-
+
FSTReader::ModelType modelType = FSTReader::predictModelType(fstMapping);
-
+
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle("Set Avatar");
QPushButton* headButton = NULL;
QPushButton* bodyButton = NULL;
QPushButton* bodyAndHeadButton = NULL;
-
+
QString modelName = fstMapping["name"].toString();
QString message;
QString typeInfo;
@@ -3982,7 +4123,7 @@ bool Application::askToSetAvatarUrl(const QString& url) {
message = QString("Would you like to use '") + modelName + QString("' for your avatar?");
bodyAndHeadButton = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole);
break;
-
+
default:
message = QString("Would you like to use '") + modelName + QString("' for some part of your avatar head?");
headButton = msgBox.addButton(tr("Use for Head"), QMessageBox::ActionRole);
@@ -4008,7 +4149,7 @@ bool Application::askToSetAvatarUrl(const QString& url) {
} else {
qCDebug(interfaceapp) << "Declined to use the avatar: " << url;
}
-
+
return true;
}
@@ -4033,7 +4174,7 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
if (isAboutToQuit()) {
return NULL;
}
-
+
QUrl scriptUrl(scriptFilename);
const QString& scriptURLString = scriptUrl.toString();
if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor
@@ -4044,18 +4185,18 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
ScriptEngine* scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface);
scriptEngine->setUserLoaded(isUserLoaded);
-
+
if (scriptFilename.isNull()) {
// this had better be the script editor (we should de-couple so somebody who thinks they are loading a script
// doesn't just get an empty script engine)
-
+
// we can complete setup now since there isn't a script we have to load
registerScriptEngineWithApplicationServices(scriptEngine);
} else {
// connect to the appropriate signals of this script engine
connect(scriptEngine, &ScriptEngine::scriptLoaded, this, &Application::handleScriptEngineLoaded);
connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &Application::handleScriptLoadError);
-
+
// get the script engine object to load the script at the designated script URL
scriptEngine->loadURL(scriptUrl);
}
@@ -4070,11 +4211,11 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
void Application::handleScriptEngineLoaded(const QString& scriptFilename) {
ScriptEngine* scriptEngine = qobject_cast(sender());
-
+
_scriptEnginesHash.insertMulti(scriptFilename, scriptEngine);
_runningScriptsWidget->setRunningScripts(getRunningScripts());
UserActivityLogger::getInstance().loadedScript(scriptFilename);
-
+
// register our application services and set it off on its own thread
registerScriptEngineWithApplicationServices(scriptEngine);
}
@@ -4184,7 +4325,7 @@ void Application::updateMyAvatarTransform() {
glm::vec3 newOriginOffset = avatarPosition;
int halfExtent = (int)HALF_SIMULATION_EXTENT;
for (int i = 0; i < 3; ++i) {
- newOriginOffset[i] = (float)(glm::max(halfExtent,
+ newOriginOffset[i] = (float)(glm::max(halfExtent,
((int)(avatarPosition[i] / SIMULATION_OFFSET_QUANTIZATION)) * (int)SIMULATION_OFFSET_QUANTIZATION));
}
// TODO: Andrew to replace this with method that actually moves existing object positions in PhysicsEngine
@@ -4198,23 +4339,23 @@ void Application::domainSettingsReceived(const QJsonObject& domainSettingsObject
const QString PER_VOXEL_COST_KEY = "per-voxel-credits";
const QString PER_METER_CUBED_COST_KEY = "per-meter-cubed-credits";
const QString VOXEL_WALLET_UUID = "voxel-wallet";
-
+
const QJsonObject& voxelObject = domainSettingsObject[VOXEL_SETTINGS_KEY].toObject();
-
+
qint64 satoshisPerVoxel = 0;
qint64 satoshisPerMeterCubed = 0;
QUuid voxelWalletUUID;
-
+
if (!domainSettingsObject.isEmpty()) {
float perVoxelCredits = (float) voxelObject[PER_VOXEL_COST_KEY].toDouble();
float perMeterCubedCredits = (float) voxelObject[PER_METER_CUBED_COST_KEY].toDouble();
-
+
satoshisPerVoxel = (qint64) floorf(perVoxelCredits * SATOSHIS_PER_CREDIT);
satoshisPerMeterCubed = (qint64) floorf(perMeterCubedCredits * SATOSHIS_PER_CREDIT);
-
+
voxelWalletUUID = QUuid(voxelObject[VOXEL_WALLET_UUID].toString());
}
-
+
qCDebug(interfaceapp) << "Octree edits costs are" << satoshisPerVoxel << "per octree cell and" << satoshisPerMeterCubed << "per meter cubed";
qCDebug(interfaceapp) << "Destination wallet UUID for edit payments is" << voxelWalletUUID;
}
@@ -4420,7 +4561,7 @@ bool Application::isVSyncOn() const {
} else {
return true;
}
- */
+ */
#endif
return true;
}
@@ -4518,14 +4659,14 @@ void Application::notifyPacketVersionMismatch() {
void Application::checkSkeleton() {
if (_myAvatar->getSkeletonModel().isActive() && !_myAvatar->getSkeletonModel().hasSkeleton()) {
qCDebug(interfaceapp) << "MyAvatar model has no skeleton";
-
+
QString message = "Your selected avatar body has no skeleton.\n\nThe default body will be loaded...";
QMessageBox msgBox;
msgBox.setText(message);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Warning);
msgBox.exec();
-
+
_myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default");
} else {
_physicsEngine.setCharacterController(_myAvatar->getCharacterController());
@@ -4538,7 +4679,7 @@ void Application::showFriendsWindow() {
const int FRIENDS_WINDOW_WIDTH = 290;
const int FRIENDS_WINDOW_HEIGHT = 500;
if (!_friendsWindow) {
- _friendsWindow = new WebWindowClass(FRIENDS_WINDOW_TITLE, FRIENDS_WINDOW_URL, FRIENDS_WINDOW_WIDTH,
+ _friendsWindow = new WebWindowClass(FRIENDS_WINDOW_TITLE, FRIENDS_WINDOW_URL, FRIENDS_WINDOW_WIDTH,
FRIENDS_WINDOW_HEIGHT, false);
connect(_friendsWindow, &WebWindowClass::closed, this, &Application::friendsWindowClosed);
}
diff --git a/interface/src/Application.h b/interface/src/Application.h
index a6bb507890..32d81bf44b 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -75,7 +75,12 @@
#include "octree/OctreeFade.h"
#include "octree/OctreePacketProcessor.h"
#include "UndoStackScriptingInterface.h"
+<<<<<<< HEAD
#include "DisplayPlugins.h"
+=======
+
+#include "render/Engine.h"
+>>>>>>> master
class QGLWidget;
class QKeyEvent;
@@ -213,7 +218,6 @@ public:
ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; }
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
EntityTreeRenderer* getEntities() { return &_entities; }
- Environment* getEnvironment() { return &_environment; }
QUndoStack* getUndoStack() { return &_undoStack; }
MainWindow* getWindow() { return _window; }
OctreeQuery& getOctreeQuery() { return _octreeQuery; }
@@ -281,9 +285,24 @@ public:
virtual void setupWorldLight();
virtual bool shouldRenderMesh(float largestDimension, float distanceToCamera);
- QImage renderAvatarBillboard();
+ QImage renderAvatarBillboard(RenderArgs* renderArgs);
+<<<<<<< HEAD
void displaySide(const Camera& camera, bool selfAvatarOnly = false);
+=======
+ void displaySide(RenderArgs* renderArgs, Camera& whichCamera, bool selfAvatarOnly = false, bool billboard = false);
+
+ /// Stores the current modelview matrix as the untranslated view matrix to use for transforms and the supplied vector as
+ /// the view matrix translation.
+ void updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation = glm::vec3());
+
+ const glm::mat4& getUntranslatedViewMatrix() const { return _untranslatedViewMatrix; }
+
+ /// Loads a view matrix that incorporates the specified model translation without the precision issues that can
+ /// result from matrix multiplication at high translation magnitudes.
+ void loadTranslatedViewMatrix(const glm::vec3& translation);
+
+>>>>>>> master
void getModelViewMatrix(glm::dmat4* modelViewMatrix);
void getProjectionMatrix(glm::dmat4* projectionMatrix);
@@ -353,6 +372,11 @@ public:
void setMaxOctreePacketsPerSecond(int maxOctreePPS);
int getMaxOctreePacketsPerSecond();
+
+ render::ScenePointer getMain3DScene() { return _main3DScene; }
+ render::EnginePointer getRenderEngine() { return _renderEngine; }
+
+ render::ScenePointer getMain3DScene() const { return _main3DScene; }
signals:
@@ -472,7 +496,9 @@ private slots:
void setCursorVisible(bool visible);
private:
- void updateCursorVisibility();
+ void resetCamerasOnResizeGL(Camera& camera, const glm::uvec2& size);
+ void updateProjectionMatrix();
+ void updateProjectionMatrix(Camera& camera, bool updateViewFrustum = true);
void sendPingPackets();
@@ -500,8 +526,8 @@ private:
glm::vec3 getSunDirection();
- void updateShadowMap();
- void renderRearViewMirror(const QRect& region, bool billboard = false);
+ void updateShadowMap(RenderArgs* renderArgs);
+ void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool billboard = false);
void setMenuShortcutsEnabled(bool enabled);
static void attachNewHeadToNode(Node *newNode);
@@ -534,7 +560,6 @@ private:
QElapsedTimer _timerStart;
QElapsedTimer _lastTimeUpdated;
bool _justStarted;
- Stars _stars;
ShapeManager _shapeManager;
PhysicalEntitySimulation _entitySimulation;
@@ -637,9 +662,6 @@ private:
TouchEvent _lastTouchEvent;
- Overlays _overlays;
- ApplicationOverlay _applicationOverlay;
-
RunningScriptsWidget* _runningScriptsWidget;
QHash _scriptEnginesHash;
bool _runningScriptsWidgetWasVisible;
@@ -675,6 +697,12 @@ private:
int _maxOctreePPS = DEFAULT_MAX_OCTREE_PPS;
quint64 _lastFaceTrackerUpdate;
+
+ render::ScenePointer _main3DScene{ new render::Scene() };
+ render::EnginePointer _renderEngine{ new render::Engine() };
+
+ Overlays _overlays;
+ ApplicationOverlay _applicationOverlay;
};
#endif // hifi_Application_h
diff --git a/interface/src/Environment.h b/interface/src/Environment.h
index fac5aa26ca..5260b979c5 100644
--- a/interface/src/Environment.h
+++ b/interface/src/Environment.h
@@ -19,7 +19,7 @@
#include "EnvironmentData.h"
-class Camera;
+class ViewFrustum;
class ProgramObject;
class Environment {
diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp
index cfc1c94995..79d49fd6f1 100644
--- a/interface/src/LODManager.cpp
+++ b/interface/src/LODManager.cpp
@@ -217,6 +217,47 @@ QString LODManager::getLODFeedbackText() {
return result;
}
+bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) {
+ const float maxScale = (float)TREE_SCALE;
+ const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it.
+ float octreeSizeScale = args->_sizeScale;
+ int boundaryLevelAdjust = args->_boundaryLevelAdjust;
+ float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio;
+ float distanceToCamera = glm::length(bounds.calcCenter() - args->_viewFrustum->getPosition());
+ float largestDimension = bounds.getLargestDimension();
+
+ static bool shouldRenderTableNeedsBuilding = true;
+ static QMap shouldRenderTable;
+ if (shouldRenderTableNeedsBuilding) {
+
+ float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small
+ float scale = maxScale;
+ float factor = 1.0f;
+
+ while (scale > SMALLEST_SCALE_IN_TABLE) {
+ scale /= 2.0f;
+ factor /= 2.0f;
+ shouldRenderTable[scale] = factor;
+ }
+
+ shouldRenderTableNeedsBuilding = false;
+ }
+
+ float closestScale = maxScale;
+ float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale;
+ QMap::const_iterator lowerBound = shouldRenderTable.lowerBound(largestDimension);
+ if (lowerBound != shouldRenderTable.constEnd()) {
+ closestScale = lowerBound.key();
+ visibleDistanceAtClosestScale = visibleDistanceAtMaxScale * lowerBound.value();
+ }
+
+ if (closestScale < largestDimension) {
+ visibleDistanceAtClosestScale *= 2.0f;
+ }
+
+ return distanceToCamera <= visibleDistanceAtClosestScale;
+};
+
// TODO: This is essentially the same logic used to render octree cells, but since models are more detailed then octree cells
// I've added a voxelToModelRatio that adjusts how much closer to a model you have to be to see it.
bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera) {
diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h
index 615bcec24d..98ababbda0 100644
--- a/interface/src/LODManager.h
+++ b/interface/src/LODManager.h
@@ -49,6 +49,8 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE;
// do. But both are still culled using the same angular size logic.
const float AVATAR_TO_ENTITY_RATIO = 2.0f;
+class RenderArgs;
+class AABox;
class LODManager : public QObject, public Dependency {
Q_OBJECT
@@ -79,6 +81,7 @@ public:
Q_INVOKABLE float getLODDecreaseFPS();
Q_INVOKABLE float getLODIncreaseFPS();
+ static bool shouldRender(const RenderArgs* args, const AABox& bounds);
bool shouldRenderMesh(float largestDimension, float distanceToCamera);
void autoAdjustLOD(float currentFPS);
diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp
index 1f217d92b9..04d83fcf3e 100644
--- a/interface/src/Util.cpp
+++ b/interface/src/Util.cpp
@@ -33,45 +33,44 @@
using namespace std;
-void renderWorldBox() {
+void renderWorldBox(gpu::Batch& batch) {
auto geometryCache = DependencyManager::get();
// Show edge of world
- glm::vec3 red(1.0f, 0.0f, 0.0f);
- glm::vec3 green(0.0f, 1.0f, 0.0f);
- glm::vec3 blue(0.0f, 0.0f, 1.0f);
- glm::vec3 grey(0.5f, 0.5f, 0.5f);
-
- glDisable(GL_LIGHTING);
- glLineWidth(1.0);
- geometryCache->renderLine(glm::vec3(0, 0, 0), glm::vec3(TREE_SCALE, 0, 0), red);
- geometryCache->renderLine(glm::vec3(0, 0, 0), glm::vec3(0, TREE_SCALE, 0), green);
- geometryCache->renderLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, TREE_SCALE), blue);
- geometryCache->renderLine(glm::vec3(0, 0, TREE_SCALE), glm::vec3(TREE_SCALE, 0, TREE_SCALE), grey);
- geometryCache->renderLine(glm::vec3(TREE_SCALE, 0, TREE_SCALE), glm::vec3(TREE_SCALE, 0, 0), grey);
+ static const glm::vec3 red(1.0f, 0.0f, 0.0f);
+ static const glm::vec3 green(0.0f, 1.0f, 0.0f);
+ static const glm::vec3 blue(0.0f, 0.0f, 1.0f);
+ static const glm::vec3 grey(0.5f, 0.5f, 0.5f);
+ auto transform = Transform{};
+ batch.setModelTransform(transform);
+ geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(TREE_SCALE, 0.0f, 0.0f), red);
+ geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, TREE_SCALE, 0.0f), green);
+ geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, TREE_SCALE), blue);
+ geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), grey);
+ geometryCache->renderLine(batch, glm::vec3(TREE_SCALE, 0.0f, TREE_SCALE), glm::vec3(TREE_SCALE, 0.0f, 0.0f), grey);
// Draw meter markers along the 3 axis to help with measuring things
const float MARKER_DISTANCE = 1.0f;
const float MARKER_RADIUS = 0.05f;
- glEnable(GL_LIGHTING);
- glPushMatrix();
- glTranslatef(MARKER_DISTANCE, 0, 0);
- geometryCache->renderSphere(MARKER_RADIUS, 10, 10, red);
- glPopMatrix();
- glPushMatrix();
- glTranslatef(0, MARKER_DISTANCE, 0);
- geometryCache->renderSphere(MARKER_RADIUS, 10, 10, green);
- glPopMatrix();
- glPushMatrix();
- glTranslatef(0, 0, MARKER_DISTANCE);
- geometryCache->renderSphere(MARKER_RADIUS, 10, 10, blue);
- glPopMatrix();
- glPushMatrix();
- glTranslatef(MARKER_DISTANCE, 0, MARKER_DISTANCE);
- geometryCache->renderSphere(MARKER_RADIUS, 10, 10, grey);
- glPopMatrix();
+
+ geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red);
+
+ transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, 0.0f));
+ batch.setModelTransform(transform);
+ geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, red);
+ transform.setTranslation(glm::vec3(0.0f, MARKER_DISTANCE, 0.0f));
+ batch.setModelTransform(transform);
+ geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, green);
+
+ transform.setTranslation(glm::vec3(0.0f, 0.0f, MARKER_DISTANCE));
+ batch.setModelTransform(transform);
+ geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, blue);
+
+ transform.setTranslation(glm::vec3(MARKER_DISTANCE, 0.0f, MARKER_DISTANCE));
+ batch.setModelTransform(transform);
+ geometryCache->renderSphere(batch, MARKER_RADIUS, 10, 10, grey);
}
// Return a random vector of average length 1
diff --git a/interface/src/Util.h b/interface/src/Util.h
index 419b776706..ed05209747 100644
--- a/interface/src/Util.h
+++ b/interface/src/Util.h
@@ -16,10 +16,12 @@
#include
#include
+#include
+
float randFloat();
const glm::vec3 randVector();
-void renderWorldBox();
+void renderWorldBox(gpu::Batch& batch);
int widthText(float scale, int mono, char const* string);
void drawText(int x, int y, float scale, float radians, int mono,
diff --git a/interface/src/audio/AudioToolBox.cpp b/interface/src/audio/AudioToolBox.cpp
index 85b8b19788..68328e151e 100644
--- a/interface/src/audio/AudioToolBox.cpp
+++ b/interface/src/audio/AudioToolBox.cpp
@@ -40,13 +40,13 @@ void AudioToolBox::render(int x, int y, int padding, bool boxed) {
glEnable(GL_TEXTURE_2D);
if (!_micTexture) {
- _micTexture = DependencyManager::get()->getImageTexture(PathUtils::resourcesPath() + "images/mic.svg");
+ _micTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic.svg");
}
if (!_muteTexture) {
- _muteTexture = DependencyManager::get()->getImageTexture(PathUtils::resourcesPath() + "images/mic-mute.svg");
+ _muteTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic-mute.svg");
}
if (_boxTexture) {
- _boxTexture = DependencyManager::get()->getImageTexture(PathUtils::resourcesPath() + "images/audio-box.svg");
+ _boxTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/audio-box.svg");
}
auto audioIO = DependencyManager::get();
diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp
index f5af137710..02af30b426 100644
--- a/interface/src/avatar/Avatar.cpp
+++ b/interface/src/avatar/Avatar.cpp
@@ -32,7 +32,7 @@
#include
#include
#include
-#include
+#include
#include
#include "Application.h"
@@ -60,6 +60,24 @@ const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME);
const float DISPLAYNAME_ALPHA = 0.95f;
const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
+namespace render {
+ template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
+ return ItemKey::Builder::opaqueShape();
+ }
+ template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
+ return static_cast(avatar.get())->getBounds();
+ }
+ template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) {
+ Avatar* avatarPtr = static_cast(avatar.get());
+ bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderLookAtVectors);
+ avatarPtr->setDisplayingLookatVectors(renderLookAtVectors);
+
+ if (avatarPtr->isInitialized() && args) {
+ avatarPtr->render(args, Application::getInstance()->getCamera()->getPosition());
+ }
+ }
+}
+
Avatar::Avatar() :
AvatarData(),
_skeletonModel(this),
@@ -116,6 +134,10 @@ glm::quat Avatar::getWorldAlignedOrientation () const {
return computeRotationFromBodyToWorldUp() * getOrientation();
}
+AABox Avatar::getBounds() const {
+ return AABox();
+}
+
float Avatar::getLODDistance() const {
return DependencyManager::get()->getAvatarLODDistanceMultiplier() *
glm::distance(qApp->getCamera()->getPosition(), _position) / _scale;
@@ -254,10 +276,10 @@ enum TextRendererType {
DISPLAYNAME
};
-static TextRenderer* textRenderer(TextRendererType type) {
- static TextRenderer* chatRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, 24, -1,
- false, TextRenderer::SHADOW_EFFECT);
- static TextRenderer* displayNameRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, 12);
+static TextRenderer3D* textRenderer(TextRendererType type) {
+ static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 24, -1,
+ false, TextRenderer3D::SHADOW_EFFECT);
+ static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, 12);
switch(type) {
case CHAT:
@@ -269,11 +291,29 @@ static TextRenderer* textRenderer(TextRendererType type) {
return displayNameRenderer;
}
-void Avatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode, bool postLighting) {
+bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) {
+ auto avatarPayload = new render::Payload(self);
+ auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
+ _renderItemID = scene->allocateID();
+ pendingChanges.resetItem(_renderItemID, avatarPayloadPointer);
+ _skeletonModel.addToScene(scene, pendingChanges);
+ getHead()->getFaceModel().addToScene(scene, pendingChanges);
+ return true;
+}
+
+void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) {
+ pendingChanges.removeItem(_renderItemID);
+ _skeletonModel.removeFromScene(scene, pendingChanges);
+ getHead()->getFaceModel().removeFromScene(scene, pendingChanges);
+}
+
+void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) {
if (_referential) {
_referential->update();
}
+ auto batch = renderArgs->_batch;
+
if (postLighting &&
glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), _position) < 10.0f) {
auto geometryCache = DependencyManager::get();
@@ -299,15 +339,11 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode rend
}
if (havePosition && haveRotation) {
- glPushMatrix(); {
- glTranslatef(position.x, position.y, position.z);
- float angle = glm::degrees(glm::angle(rotation));
- glm::vec3 axis = glm::axis(rotation);
- glRotatef(angle, axis.x, axis.y, axis.z);
-
- geometryCache->renderLine(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
-
- } glPopMatrix();
+ Transform pointerTransform;
+ pointerTransform.setTranslation(position);
+ pointerTransform.setRotation(rotation);
+ batch->setModelTransform(pointerTransform);
+ geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
}
}
@@ -325,14 +361,11 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode rend
}
if (havePosition && haveRotation) {
- glPushMatrix(); {
- glTranslatef(position.x, position.y, position.z);
- float angle = glm::degrees(glm::angle(rotation));
- glm::vec3 axis = glm::axis(rotation);
- glRotatef(angle, axis.x, axis.y, axis.z);
- geometryCache->renderLine(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
-
- } glPopMatrix();
+ Transform pointerTransform;
+ pointerTransform.setTranslation(position);
+ pointerTransform.setRotation(rotation);
+ batch->setModelTransform(pointerTransform);
+ geometryCache->renderLine(*batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
}
}
}
@@ -340,7 +373,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode rend
// simple frustum check
float boundingRadius = getBillboardSize();
ViewFrustum* frustum = nullptr;
- if (renderMode == RenderArgs::SHADOW_RENDER_MODE) {
+ if (renderArgs->_renderMode == RenderArgs::SHADOW_RENDER_MODE) {
frustum = Application::getInstance()->getShadowViewFrustum();
} else {
frustum = Application::getInstance()->getDisplayViewFrustum();
@@ -366,14 +399,14 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode rend
GLOW_FROM_AVERAGE_LOUDNESS = 0.0f;
}
- float glowLevel = _moving && distanceToTarget > GLOW_DISTANCE && renderMode == RenderArgs::NORMAL_RENDER_MODE
+ float glowLevel = _moving && distanceToTarget > GLOW_DISTANCE && renderArgs->_renderMode == RenderArgs::NORMAL_RENDER_MODE
? 1.0f
: GLOW_FROM_AVERAGE_LOUDNESS;
// render body
- renderBody(frustum, renderMode, postLighting, glowLevel);
+ renderBody(renderArgs, frustum, postLighting, glowLevel);
- if (!postLighting && renderMode != RenderArgs::SHADOW_RENDER_MODE) {
+ if (!postLighting && renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) {
// add local lights
const float BASE_LIGHT_DISTANCE = 2.0f;
const float LIGHT_EXPONENT = 1.0f;
@@ -397,10 +430,10 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode rend
_skeletonModel.renderJointCollisionShapes(0.7f);
}
- if (renderHead && shouldRenderHead(cameraPosition, renderMode)) {
+ if (renderHead && shouldRenderHead(renderArgs, cameraPosition)) {
getHead()->getFaceModel().renderJointCollisionShapes(0.7f);
}
- if (renderBounding && shouldRenderHead(cameraPosition, renderMode)) {
+ if (renderBounding && shouldRenderHead(renderArgs, cameraPosition)) {
_skeletonModel.renderBoundingCollisionShapes(0.7f);
}
@@ -409,14 +442,16 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode rend
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 };
- glPushMatrix();
+ glm::vec3 position;
if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) {
- glTranslatef(_position.x, getDisplayNamePosition().y, _position.z);
+ position = glm::vec3(_position.x, getDisplayNamePosition().y, _position.z);
} else {
- glTranslatef(_position.x, getDisplayNamePosition().y + LOOK_AT_INDICATOR_OFFSET, _position.z);
+ position = glm::vec3(_position.x, getDisplayNamePosition().y + LOOK_AT_INDICATOR_OFFSET, _position.z);
}
- DependencyManager::get()->renderSphere(LOOK_AT_INDICATOR_RADIUS, 15, 15, LOOK_AT_INDICATOR_COLOR);
- glPopMatrix();
+ Transform transform;
+ transform.setTranslation(position);
+ batch->setModelTransform(transform);
+ DependencyManager::get()->renderSphere(*batch, LOOK_AT_INDICATOR_RADIUS, 15, 15, LOOK_AT_INDICATOR_COLOR);
}
}
@@ -437,31 +472,33 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode rend
float angle = abs(angleBetween(toTarget + delta, toTarget - delta));
float sphereRadius = getHead()->getAverageLoudness() * SPHERE_LOUDNESS_SCALING;
- if (renderMode == RenderArgs::NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) &&
+ if (renderArgs->_renderMode == RenderArgs::NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) &&
(angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) {
- glPushMatrix();
- glTranslatef(_position.x, _position.y, _position.z);
- glScalef(height, height, height);
+ Transform transform;
+ transform.setTranslation(_position);
+ transform.setScale(height);
+ batch->setModelTransform(transform);
if (_voiceSphereID == GeometryCache::UNKNOWN_ID) {
_voiceSphereID = DependencyManager::get()->allocateID();
}
- DependencyManager::get()->renderSphere(sphereRadius, 15, 15,
+
+ DependencyManager::get()->renderSphere(*batch, sphereRadius, 15, 15,
glm::vec4(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE), true,
_voiceSphereID);
-
- glPopMatrix();
}
}
}
const float DISPLAYNAME_DISTANCE = 20.0f;
- setShowDisplayName(renderMode == RenderArgs::NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE);
- if (!postLighting || renderMode != RenderArgs::NORMAL_RENDER_MODE || (isMyAvatar() &&
+ setShowDisplayName(renderArgs->_renderMode == RenderArgs::NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE);
+
+ if (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE || (isMyAvatar() &&
Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) {
return;
}
- renderDisplayName();
+
+ renderDisplayName(renderArgs);
}
glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
@@ -480,32 +517,44 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
return glm::angleAxis(angle * proportion, axis);
}
-void Avatar::renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode renderMode, bool postLighting, float glowLevel) {
- Model::RenderMode modelRenderMode = renderMode;
+void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) {
+ // check to see if when we added our models to the scene they were ready, if they were not ready, then
+ // fix them up in the scene
+ render::ScenePointer scene = Application::getInstance()->getMain3DScene();
+ render::PendingChanges pendingChanges;
+ if (_skeletonModel.needsFixupInScene()) {
+ _skeletonModel.removeFromScene(scene, pendingChanges);
+ _skeletonModel.addToScene(scene, pendingChanges);
+ }
+ if (getHead()->getFaceModel().needsFixupInScene()) {
+ getHead()->getFaceModel().removeFromScene(scene, pendingChanges);
+ getHead()->getFaceModel().addToScene(scene, pendingChanges);
+ }
+ scene->enqueuePendingChanges(pendingChanges);
+
{
- Glower glower(glowLevel);
+ Glower glower(renderArgs, glowLevel);
if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
- if (postLighting || renderMode == RenderArgs::SHADOW_RENDER_MODE) {
+ if (postLighting || renderArgs->_renderMode == RenderArgs::SHADOW_RENDER_MODE) {
// render the billboard until both models are loaded
- renderBillboard();
+ renderBillboard(renderArgs);
}
return;
}
if (postLighting) {
- getHand()->render(false, modelRenderMode);
+ getHand()->render(renderArgs, false);
} else {
- RenderArgs args;
- args._viewFrustum = renderFrustum;
- _skeletonModel.render(1.0f, modelRenderMode, &args);
- renderAttachments(renderMode, &args);
+ // NOTE: we no longer call this here, because we've added all the model parts as renderable items in the scene
+ //_skeletonModel.render(renderArgs, 1.0f);
+ renderAttachments(renderArgs);
}
}
- getHead()->render(1.0f, renderFrustum, modelRenderMode, postLighting);
+ getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting);
}
-bool Avatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) const {
+bool Avatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const {
return true;
}
@@ -529,19 +578,21 @@ void Avatar::simulateAttachments(float deltaTime) {
}
}
-void Avatar::renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args) {
+void Avatar::renderAttachments(RenderArgs* args) {
// RenderArgs::RenderMode modelRenderMode = (renderMode == RenderArgs::SHADOW_RENDER_MODE) ?
// RenderArgs::SHADOW_RENDER_MODE : RenderArgs::DEFAULT_RENDER_MODE;
+ /*
foreach (Model* model, _attachmentModels) {
- model->render(1.0f, renderMode, args);
+ model->render(args, 1.0f);
}
+ */
}
void Avatar::updateJointMappings() {
// no-op; joint mappings come from skeleton model
}
-void Avatar::renderBillboard() {
+void Avatar::renderBillboard(RenderArgs* renderArgs) {
if (_billboard.isEmpty()) {
return;
}
@@ -554,44 +605,29 @@ void Avatar::renderBillboard() {
if (!_billboardTexture->isLoaded()) {
return;
}
-
- glEnable(GL_ALPHA_TEST);
- glAlphaFunc(GL_GREATER, 0.5f);
-
- glEnable(GL_TEXTURE_2D);
- glDisable(GL_LIGHTING);
-
- glBindTexture(GL_TEXTURE_2D, _billboardTexture->getID());
-
- glPushMatrix();
- glTranslatef(_position.x, _position.y, _position.z);
-
// rotate about vertical to face the camera
glm::quat rotation = getOrientation();
glm::vec3 cameraVector = glm::inverse(rotation) * (Application::getInstance()->getCamera()->getPosition() - _position);
rotation = rotation * glm::angleAxis(atan2f(-cameraVector.x, -cameraVector.z), glm::vec3(0.0f, 1.0f, 0.0f));
- glm::vec3 axis = glm::axis(rotation);
- glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
-
+
// compute the size from the billboard camera parameters and scale
float size = getBillboardSize();
- glScalef(size, size, size);
+
+ Transform transform;
+ transform.setTranslation(_position);
+ transform.setRotation(rotation);
+ transform.setScale(size);
glm::vec2 topLeft(-1.0f, -1.0f);
glm::vec2 bottomRight(1.0f, 1.0f);
glm::vec2 texCoordTopLeft(0.0f, 0.0f);
glm::vec2 texCoordBottomRight(1.0f, 1.0f);
-
- DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
+
+ gpu::Batch& batch = *renderArgs->_batch;
+ batch.setUniformTexture(0, _billboardTexture->getGPUTexture());
+ DependencyManager::get()->bindSimpleProgram(batch, true);
+ DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
-
- glPopMatrix();
-
- glDisable(GL_TEXTURE_2D);
- glEnable(GL_LIGHTING);
- glDisable(GL_ALPHA_TEST);
-
- glBindTexture(GL_TEXTURE_2D, 0);
}
float Avatar::getBillboardSize() const {
@@ -654,9 +690,10 @@ float Avatar::calculateDisplayNameScaleFactor(const glm::vec3& textPosition, boo
return scaleFactor;
}
-void Avatar::renderDisplayName() {
+void Avatar::renderDisplayName(RenderArgs* renderArgs) {
+ auto batch = renderArgs->_batch;
- bool shouldShowReceiveStats = DependencyManager::get()->shouldShowReceiveStats();
+ bool shouldShowReceiveStats = DependencyManager::get()->shouldShowReceiveStats() && !isMyAvatar();
if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) {
return;
@@ -665,31 +702,19 @@ void Avatar::renderDisplayName() {
// which viewing mode?
bool inHMD = Application::getInstance()->isHMDMode();
- glDisable(GL_LIGHTING);
-
- glPushMatrix();
glm::vec3 textPosition = getDisplayNamePosition();
- glTranslatef(textPosition.x, textPosition.y, textPosition.z);
-
- // we need "always facing camera": we must remove the camera rotation from the stack
-
-
- glm::vec3 frontAxis(0.0f, 0.0f, 1.0f);
- if (inHMD) {
- glm::vec3 camPosition = Application::getInstance()->getCamera()->getPosition();
- frontAxis = camPosition - textPosition;
- } else {
- glm::quat rotation = Application::getInstance()->getCamera()->getRotation();
- frontAxis = glm::rotate(rotation, frontAxis);
- }
-
- frontAxis = glm::normalize(glm::vec3(frontAxis.z, 0.0f, -frontAxis.x));
- float angle = acos(frontAxis.x) * ((frontAxis.z < 0) ? 1.0f : -1.0f);
- glRotatef(glm::degrees(angle), 0.0f, 1.0f, 0.0f);
+ // we need "always facing camera": we must remove the camera rotation from the stac
+ glm::quat rotation = Application::getInstance()->getCamera()->getRotation();
+ // TODO: Fix scaling - at some point this or the text rendering changed in scale.
float scaleFactor = calculateDisplayNameScaleFactor(textPosition, inHMD);
- glScalef(scaleFactor, -scaleFactor, scaleFactor); // TextRenderer::draw paints the text upside down in y axis
+ scaleFactor /= 3.5f;
+
+ Transform textTransform;
+ textTransform.setTranslation(textPosition);
+ textTransform.setRotation(rotation);
+ textTransform.setScale(scaleFactor);
// optionally render timing stats for this avatar with the display name
QString renderedDisplayName = _displayName;
@@ -699,55 +724,45 @@ void Avatar::renderDisplayName() {
float kilobitsPerSecond = getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT;
QString statsFormat = QString("(%1 Kbps, %2 Hz)");
-
if (!renderedDisplayName.isEmpty()) {
statsFormat.prepend(" - ");
}
QString statsText = statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate());
- glm::vec2 extent = textRenderer(DISPLAYNAME)->computeExtent(statsText);
-
- // add the extent required for the stats to whatever was calculated for the display name
- nameDynamicRect.setWidth(nameDynamicRect.width() + extent.x);
-
- if (extent.y > nameDynamicRect.height()) {
- nameDynamicRect.setHeight(extent.y);
- }
-
renderedDisplayName += statsText;
+
+ glm::vec2 extent = textRenderer(DISPLAYNAME)->computeExtent(renderedDisplayName);
+ nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
}
int text_x = -nameDynamicRect.width() / 2;
int text_y = -nameDynamicRect.height() / 2;
// draw a gray background
- int left = text_x + nameDynamicRect.x();
+ int left = text_x;
int right = left + nameDynamicRect.width();
- int bottom = text_y + nameDynamicRect.y();
+ int bottom = text_y;
int top = bottom + nameDynamicRect.height();
const int border = 8;
bottom -= border;
left -= border;
top += border;
right += border;
-
- // We are drawing coplanar textures with depth: need the polygon offset
- glEnable(GL_POLYGON_OFFSET_FILL);
- glPolygonOffset(1.0f, 1.0f);
-
- DependencyManager::get()->renderBevelCornersRect(left, bottom, right - left, top - bottom, 3,
- glm::vec4(0.2f, 0.2f, 0.2f, _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA));
-
- glm::vec4 color(0.93f, 0.93f, 0.93f, _displayNameAlpha);
-
+
+ glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha);
+ glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,
+ _displayNameAlpha * DISPLAYNAME_BACKGROUND_ALPHA / DISPLAYNAME_ALPHA);
+
+ auto backgroundTransform = textTransform;
+ backgroundTransform.postTranslate(glm::vec3(0.0f, 0.0f, -0.001f));
+ batch->setModelTransform(backgroundTransform);
+ DependencyManager::get()->bindSimpleProgram(*batch);
+ DependencyManager::get()->renderBevelCornersRect(*batch, left, bottom, right - left, top - bottom, 3,
+ backgroundColor);
QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
- glDisable(GL_POLYGON_OFFSET_FILL);
- textRenderer(DISPLAYNAME)->draw(text_x, text_y, nameUTF8.data(), color);
-
- glPopMatrix();
-
- glEnable(GL_LIGHTING);
+ batch->setModelTransform(textTransform);
+ textRenderer(DISPLAYNAME)->draw(*batch, text_x, -text_y, nameUTF8.data(), textColor);
}
bool Avatar::findRayIntersection(RayIntersectionInfo& intersection) const {
@@ -1050,13 +1065,13 @@ float Avatar::getSkeletonHeight() const {
float Avatar::getHeadHeight() const {
Extents extents = getHead()->getFaceModel().getMeshExtents();
- if (!extents.isEmpty()) {
+ if (!extents.isEmpty() && extents.isValid()) {
return extents.maximum.y - extents.minimum.y;
}
extents = _skeletonModel.getMeshExtents();
glm::vec3 neckPosition;
- if (!extents.isEmpty() && _skeletonModel.getNeckPosition(neckPosition)) {
+ if (!extents.isEmpty() && extents.isValid() && _skeletonModel.getNeckPosition(neckPosition)) {
return extents.maximum.y / 2.0f - neckPosition.y + _position.y;
}
diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h
index 3c784fb925..dbc59f7d9c 100644
--- a/interface/src/avatar/Avatar.h
+++ b/interface/src/avatar/Avatar.h
@@ -20,12 +20,20 @@
#include
#include
+#include
+
#include "Hand.h"
#include "Head.h"
#include "InterfaceConfig.h"
#include "SkeletonModel.h"
#include "world.h"
+namespace render {
+ template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar);
+ template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar);
+ template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args);
+}
+
static const float SCALING_RATIO = .05f;
static const float SMOOTHING_RATIO = .05f; // 0 < ratio < 1
static const float RESCALING_TOLERANCE = .02f;
@@ -66,12 +74,21 @@ public:
Avatar();
~Avatar();
+ typedef render::Payload Payload;
+ typedef std::shared_ptr PayloadPointer;
+
void init();
void simulate(float deltaTime);
- virtual void render(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode = RenderArgs::NORMAL_RENDER_MODE,
+ virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition,
bool postLighting = false);
+ bool addToScene(AvatarSharedPointer self, std::shared_ptr scene,
+ render::PendingChanges& pendingChanges);
+
+ void removeFromScene(AvatarSharedPointer self, std::shared_ptr scene,
+ render::PendingChanges& pendingChanges);
+
//setters
void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); }
void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; }
@@ -87,6 +104,8 @@ public:
Hand* getHand() { return static_cast(_handData); }
glm::quat getWorldAlignedOrientation() const;
+ AABox getBounds() const;
+
/// Returns the distance to use as a LOD parameter.
float getLODDistance() const;
@@ -212,23 +231,24 @@ protected:
glm::vec3 getDisplayNamePosition();
float calculateDisplayNameScaleFactor(const glm::vec3& textPosition, bool inHMD);
- void renderDisplayName();
- virtual void renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
- virtual bool shouldRenderHead(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) const;
+ void renderDisplayName(RenderArgs* renderArgs);
+ virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f);
+ virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const;
void simulateAttachments(float deltaTime);
- virtual void renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args);
+ virtual void renderAttachments(RenderArgs* args);
virtual void updateJointMappings();
+
+ render::ItemID _renderItemID;
private:
-
bool _initialized;
NetworkTexturePointer _billboardTexture;
bool _shouldRenderBillboard;
bool _isLookAtTarget;
- void renderBillboard();
+ void renderBillboard(RenderArgs* renderArgs);
float getBillboardSize() const;
diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index 3c8aad3f5d..f16173b79e 100644
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -55,12 +55,17 @@ AvatarManager::AvatarManager(QObject* parent) :
_avatarFades() {
// register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar
qRegisterMetaType >("NodeWeakPointer");
- _myAvatar = QSharedPointer(new MyAvatar());
+ _myAvatar = std::make_shared();
}
void AvatarManager::init() {
_myAvatar->init();
_avatarHash.insert(MY_AVATAR_KEY, _myAvatar);
+
+ render::ScenePointer scene = Application::getInstance()->getMain3DScene();
+ render::PendingChanges pendingChanges;
+ _myAvatar->addToScene(_myAvatar, scene, pendingChanges);
+ scene->enqueuePendingChanges(pendingChanges);
}
void AvatarManager::updateMyAvatar(float deltaTime) {
@@ -92,7 +97,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
// simulate avatars
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {
- Avatar* avatar = reinterpret_cast(avatarIterator.value().data());
+ auto avatar = std::dynamic_pointer_cast(avatarIterator.value());
if (avatar == _myAvatar || !avatar->isInitialized()) {
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
@@ -111,69 +116,39 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
simulateAvatarFades(deltaTime);
}
-void AvatarManager::renderAvatars(RenderArgs::RenderMode renderMode, bool postLighting, bool selfAvatarOnly) {
- PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
- "Application::renderAvatars()");
- bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderLookAtVectors);
-
- glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition();
-
- if (!selfAvatarOnly) {
- if (DependencyManager::get()->shouldRenderAvatars()) {
- foreach (const AvatarSharedPointer& avatarPointer, _avatarHash) {
- Avatar* avatar = static_cast(avatarPointer.data());
- if (!avatar->isInitialized()) {
- continue;
- }
- avatar->render(cameraPosition, renderMode, postLighting);
- avatar->setDisplayingLookatVectors(renderLookAtVectors);
- }
- renderAvatarFades(cameraPosition, renderMode);
- }
- } else {
- // just render myAvatar
- _myAvatar->render(cameraPosition, renderMode, postLighting);
- _myAvatar->setDisplayingLookatVectors(renderLookAtVectors);
- }
-}
-
void AvatarManager::simulateAvatarFades(float deltaTime) {
QVector::iterator fadingIterator = _avatarFades.begin();
const float SHRINK_RATE = 0.9f;
const float MIN_FADE_SCALE = 0.001f;
-
+
+ render::ScenePointer scene = Application::getInstance()->getMain3DScene();
+ render::PendingChanges pendingChanges;
while (fadingIterator != _avatarFades.end()) {
- Avatar* avatar = static_cast(fadingIterator->data());
+ auto avatar = std::static_pointer_cast(*fadingIterator);
avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true);
if (avatar->getTargetScale() < MIN_FADE_SCALE) {
+ avatar->removeFromScene(*fadingIterator, scene, pendingChanges);
fadingIterator = _avatarFades.erase(fadingIterator);
} else {
avatar->simulate(deltaTime);
++fadingIterator;
}
}
-}
-
-void AvatarManager::renderAvatarFades(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) {
- // render avatar fades
- Glower glower(renderMode == RenderArgs::NORMAL_RENDER_MODE ? 1.0f : 0.0f);
-
- foreach(const AvatarSharedPointer& fadingAvatar, _avatarFades) {
- Avatar* avatar = static_cast(fadingAvatar.data());
- if (avatar != static_cast(_myAvatar.data()) && avatar->isInitialized()) {
- avatar->render(cameraPosition, renderMode);
- }
- }
+ scene->enqueuePendingChanges(pendingChanges);
}
AvatarSharedPointer AvatarManager::newSharedAvatar() {
- return AvatarSharedPointer(new Avatar());
+ return AvatarSharedPointer(std::make_shared());
}
// virtual
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) {
- AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer);
+ auto avatar = std::dynamic_pointer_cast(AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer));
+ render::ScenePointer scene = Application::getInstance()->getMain3DScene();
+ render::PendingChanges pendingChanges;
+ avatar->addToScene(avatar, scene, pendingChanges);
+ scene->enqueuePendingChanges(pendingChanges);
return avatar;
}
@@ -194,10 +169,9 @@ void AvatarManager::removeAvatarMotionState(Avatar* avatar) {
void AvatarManager::removeAvatar(const QUuid& sessionUUID) {
AvatarHash::iterator avatarIterator = _avatarHash.find(sessionUUID);
if (avatarIterator != _avatarHash.end()) {
- Avatar* avatar = reinterpret_cast(avatarIterator.value().data());
+ std::shared_ptr avatar = std::dynamic_pointer_cast(avatarIterator.value());
if (avatar != _myAvatar && avatar->isInitialized()) {
- removeAvatarMotionState(avatar);
-
+ removeAvatarMotionState(avatar.get());
_avatarFades.push_back(avatarIterator.value());
_avatarHash.erase(avatarIterator);
}
@@ -208,12 +182,12 @@ void AvatarManager::clearOtherAvatars() {
// clear any avatars that came from an avatar-mixer
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {
- Avatar* avatar = reinterpret_cast(avatarIterator.value().data());
+ auto avatar = std::static_pointer_cast(avatarIterator.value());
if (avatar == _myAvatar || !avatar->isInitialized()) {
// don't remove myAvatar or uninitialized avatars from the list
++avatarIterator;
} else {
- removeAvatarMotionState(avatar);
+ removeAvatarMotionState(avatar.get());
_avatarFades.push_back(avatarIterator.value());
avatarIterator = _avatarHash.erase(avatarIterator);
}
@@ -276,7 +250,7 @@ void AvatarManager::handleCollisionEvents(CollisionEvents& collisionEvents) {
void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) {
AvatarHash::iterator avatarItr = _avatarHash.find(id);
if (avatarItr != _avatarHash.end()) {
- Avatar* avatar = static_cast(avatarItr.value().data());
+ auto avatar = std::static_pointer_cast(avatarItr.value());
AvatarMotionState* motionState = avatar->_motionState;
if (motionState) {
motionState->addDirtyFlags(EntityItem::DIRTY_SHAPE);
@@ -285,7 +259,7 @@ void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) {
avatar->computeShapeInfo(shapeInfo);
btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo);
if (shape) {
- AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
+ AvatarMotionState* motionState = new AvatarMotionState(avatar.get(), shape);
avatar->_motionState = motionState;
_motionStatesToAdd.insert(motionState);
_avatarMotionStates.insert(motionState);
diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h
index 51eb3a8ec2..b4482c5a34 100644
--- a/interface/src/avatar/AvatarManager.h
+++ b/interface/src/avatar/AvatarManager.h
@@ -35,11 +35,10 @@ public:
void init();
- MyAvatar* getMyAvatar() { return _myAvatar.data(); }
+ MyAvatar* getMyAvatar() { return _myAvatar.get(); }
void updateMyAvatar(float deltaTime);
void updateOtherAvatars(float deltaTime);
- void renderAvatars(RenderArgs::RenderMode renderMode, bool postLighting = false, bool selfAvatarOnly = false);
void clearOtherAvatars();
@@ -70,7 +69,6 @@ private:
AvatarManager(const AvatarManager& other);
void simulateAvatarFades(float deltaTime);
- void renderAvatarFades(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode);
// virtual overrides
virtual AvatarSharedPointer newSharedAvatar();
@@ -79,7 +77,7 @@ private:
virtual void removeAvatar(const QUuid& sessionUUID);
QVector _avatarFades;
- QSharedPointer _myAvatar;
+ std::shared_ptr _myAvatar;
quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate.
QVector _localLights;
diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp
index 722f998f86..1501c52de5 100644
--- a/interface/src/avatar/FaceModel.cpp
+++ b/interface/src/avatar/FaceModel.cpp
@@ -39,7 +39,8 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
setPupilDilation(_owningHead->getPupilDilation());
setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients());
- invalidCalculatedMeshBoxes();
+ // FIXME - this is very expensive, we shouldn't do it if we don't have to
+ //invalidCalculatedMeshBoxes();
if (isActive()) {
setOffset(-_geometry->getFBXGeometry().neckPivot);
diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp
index e67ed15b67..74653d9768 100644
--- a/interface/src/avatar/Hand.cpp
+++ b/interface/src/avatar/Hand.cpp
@@ -102,8 +102,8 @@ void Hand::resolvePenetrations() {
}
}
-void Hand::render(bool isMine, Model::RenderMode renderMode) {
- if (renderMode != RenderArgs::SHADOW_RENDER_MODE &&
+void Hand::render(RenderArgs* renderArgs, bool isMine) {
+ if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE &&
Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) {
// draw a green sphere at hand joint location, which is actually near the wrist)
for (size_t i = 0; i < getNumPalms(); i++) {
@@ -119,7 +119,7 @@ void Hand::render(bool isMine, Model::RenderMode renderMode) {
}
}
- if (renderMode != RenderArgs::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) {
+ if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) {
renderHandTargets(isMine);
}
diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h
index e19f5674b4..cb35497960 100644
--- a/interface/src/avatar/Hand.h
+++ b/interface/src/avatar/Hand.h
@@ -40,19 +40,8 @@ class Hand : public HandData {
public:
Hand(Avatar* owningAvatar);
- struct HandBall
- {
- glm::vec3 position; // the actual dynamic position of the ball at any given time
- glm::quat rotation; // the rotation of the ball
- glm::vec3 velocity; // the velocity of the ball
- float radius; // the radius of the ball
- bool isCollidable; // whether or not the ball responds to collisions
- bool isColliding; // ball is currently colliding
- float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball
- };
-
void simulate(float deltaTime, bool isMine);
- void render(bool isMine, Model::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE);
+ void render(RenderArgs* renderArgs, bool isMine);
void collideAgainstAvatar(Avatar* avatar, bool isMyHand);
diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp
index 8691243c07..0982a33826 100644
--- a/interface/src/avatar/Head.cpp
+++ b/interface/src/avatar/Head.cpp
@@ -292,15 +292,11 @@ void Head::relaxLean(float deltaTime) {
_deltaLeanForward *= relaxationFactor;
}
-void Head::render(float alpha, ViewFrustum* renderFrustum, Model::RenderMode mode, bool postLighting) {
+void Head::render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum, bool postLighting) {
if (postLighting) {
if (_renderLookatVectors) {
- renderLookatVectors(_leftEyePosition, _rightEyePosition, getCorrectedLookAtPosition());
+ renderLookatVectors(renderArgs, _leftEyePosition, _rightEyePosition, getCorrectedLookAtPosition());
}
- } else {
- RenderArgs args;
- args._viewFrustum = renderFrustum;
- _faceModel.render(alpha, mode, &args);
}
}
@@ -383,9 +379,9 @@ void Head::addLeanDeltas(float sideways, float forward) {
_deltaLeanForward += forward;
}
-void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
+void Head::renderLookatVectors(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
auto geometryCache = DependencyManager::get();
- DependencyManager::get()->begin();
+ DependencyManager::get()->begin(renderArgs);
glLineWidth(2.0);
@@ -394,7 +390,7 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi
geometryCache->renderLine(leftEyePosition, lookatPosition, startColor, endColor, _leftEyeLookAtID);
geometryCache->renderLine(rightEyePosition, lookatPosition, startColor, endColor, _rightEyeLookAtID);
- DependencyManager::get()->end();
+ DependencyManager::get()->end(renderArgs);
}
diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h
index 6eba16824e..a208574c26 100644
--- a/interface/src/avatar/Head.h
+++ b/interface/src/avatar/Head.h
@@ -40,7 +40,7 @@ public:
void init();
void reset();
void simulate(float deltaTime, bool isMine, bool billboard = false);
- void render(float alpha, ViewFrustum* renderFrustum, Model::RenderMode mode, bool postLighting);
+ void render(RenderArgs* renderArgs, float alpha, ViewFrustum* renderFrustum, bool postLighting);
void setScale(float scale);
void setPosition(glm::vec3 position) { _position = position; }
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }
@@ -153,7 +153,7 @@ private:
int _rightEyeLookAtID;
// private methods
- void renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition);
+ void renderLookatVectors(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition);
void calculateMouthShapes();
void applyEyelidOffset(glm::quat headOrientation);
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index e573110157..8a49d69129 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -45,6 +45,9 @@
#include "Util.h"
#include "InterfaceLogging.h"
+#include "gpu/GLBackend.h"
+
+
using namespace std;
const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);
@@ -105,7 +108,7 @@ MyAvatar::MyAvatar() :
}
MyAvatar::~MyAvatar() {
- _lookAtTargetAvatar.clear();
+ _lookAtTargetAvatar.reset();
}
QByteArray MyAvatar::toByteArray() {
@@ -328,14 +331,14 @@ void MyAvatar::renderDebugBodyPoints() {
}
// virtual
-void MyAvatar::render(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode, bool postLighting) {
+void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) {
// don't render if we've been asked to disable local rendering
if (!_shouldRender) {
return; // exit early
}
- Avatar::render(cameraPosition, renderMode, postLighting);
-
+ Avatar::render(renderArgs, cameraPosition, postLighting);
+
// don't display IK constraints in shadow mode
if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && postLighting) {
_skeletonModel.renderIKConstraints();
@@ -856,7 +859,7 @@ void MyAvatar::updateLookAtTargetAvatar() {
//
// Look at the avatar whose eyes are closest to the ray in direction of my avatar's head
//
- _lookAtTargetAvatar.clear();
+ _lookAtTargetAvatar.reset();
_targetAvatarPosition = glm::vec3(0.0f);
glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FRONT;
@@ -868,7 +871,7 @@ void MyAvatar::updateLookAtTargetAvatar() {
int howManyLookingAtMe = 0;
foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get()->getAvatarHash()) {
- Avatar* avatar = static_cast(avatarPointer.data());
+ Avatar* avatar = static_cast(avatarPointer.get());
bool isCurrentTarget = avatar->getIsLookAtTarget();
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
avatar->setIsLookAtTarget(false);
@@ -896,13 +899,14 @@ void MyAvatar::updateLookAtTargetAvatar() {
}
}
}
- if (_lookAtTargetAvatar) {
- static_cast(_lookAtTargetAvatar.data())->setIsLookAtTarget(true);
+ auto avatarPointer = _lookAtTargetAvatar.lock();
+ if (avatarPointer) {
+ static_cast(avatarPointer.get())->setIsLookAtTarget(true);
}
}
void MyAvatar::clearLookAtTargetAvatar() {
- _lookAtTargetAvatar.clear();
+ _lookAtTargetAvatar.reset();
}
bool MyAvatar::isLookingAtLeftEye() {
@@ -1166,11 +1170,26 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, const g
Avatar::attach(modelURL, jointName, translation, rotation, scale, allowDuplicates, useSaved);
}
-void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode renderMode, bool postLighting, float glowLevel) {
+void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel) {
+
if (!(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
return; // wait until both models are loaded
}
+ // check to see if when we added our models to the scene they were ready, if they were not ready, then
+ // fix them up in the scene
+ render::ScenePointer scene = Application::getInstance()->getMain3DScene();
+ render::PendingChanges pendingChanges;
+ if (_skeletonModel.needsFixupInScene()) {
+ _skeletonModel.removeFromScene(scene, pendingChanges);
+ _skeletonModel.addToScene(scene, pendingChanges);
+ }
+ if (getHead()->getFaceModel().needsFixupInScene()) {
+ getHead()->getFaceModel().removeFromScene(scene, pendingChanges);
+ getHead()->getFaceModel().addToScene(scene, pendingChanges);
+ }
+ scene->enqueuePendingChanges(pendingChanges);
+
Camera *camera = Application::getInstance()->getCamera();
const glm::vec3 cameraPos = camera->getPosition();
@@ -1190,28 +1209,27 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode ren
}*/
// Render the body's voxels and head
- RenderArgs::RenderMode modelRenderMode = renderMode;
if (!postLighting) {
- RenderArgs args;
- args._viewFrustum = renderFrustum;
- _skeletonModel.render(1.0f, modelRenderMode, &args);
- renderAttachments(renderMode, &args);
+
+ // NOTE: we no longer call this here, because we've added all the model parts as renderable items in the scene
+ //_skeletonModel.render(renderArgs, 1.0f);
+ renderAttachments(renderArgs);
}
// Render head so long as the camera isn't inside it
- if (shouldRenderHead(cameraPos, renderMode)) {
- getHead()->render(1.0f, renderFrustum, modelRenderMode, postLighting);
+ if (shouldRenderHead(renderArgs, cameraPos)) {
+ getHead()->render(renderArgs, 1.0f, renderFrustum, postLighting);
}
if (postLighting) {
- getHand()->render(true, modelRenderMode);
+ getHand()->render(renderArgs, true);
}
}
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
-bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) const {
+bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const {
const Head* head = getHead();
- return (renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
+ return (renderArgs->_renderMode != RenderArgs::NORMAL_RENDER_MODE) || (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON) ||
(glm::length(cameraPosition - head->getEyePosition()) > RENDER_HEAD_CUTOFF_DISTANCE * _scale);
}
@@ -1474,7 +1492,9 @@ void MyAvatar::maybeUpdateBillboard() {
return;
}
}
- QImage image = Application::getInstance()->renderAvatarBillboard();
+ gpu::Context context(new gpu::GLBackend());
+ RenderArgs renderArgs(&context);
+ QImage image = Application::getInstance()->renderAvatarBillboard(&renderArgs);
_billboard.clear();
QBuffer buffer(&_billboard);
buffer.open(QIODevice::WriteOnly);
@@ -1551,21 +1571,25 @@ void MyAvatar::updateMotionBehavior() {
_feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations);
}
-void MyAvatar::renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args) {
- if (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON || renderMode == RenderArgs::MIRROR_RENDER_MODE) {
- Avatar::renderAttachments(renderMode, args);
+void MyAvatar::renderAttachments(RenderArgs* args) {
+ if (Application::getInstance()->getCamera()->getMode() != CAMERA_MODE_FIRST_PERSON || args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
+ Avatar::renderAttachments(args);
return;
}
const FBXGeometry& geometry = _skeletonModel.getGeometry()->getFBXGeometry();
QString headJointName = (geometry.headJointIndex == -1) ? QString() : geometry.joints.at(geometry.headJointIndex).name;
// RenderArgs::RenderMode modelRenderMode = (renderMode == RenderArgs::SHADOW_RENDER_MODE) ?
// RenderArgs::SHADOW_RENDER_MODE : RenderArgs::DEFAULT_RENDER_MODE;
+
+ // FIX ME - attachments need to be added to scene too...
+ /*
for (int i = 0; i < _attachmentData.size(); i++) {
const QString& jointName = _attachmentData.at(i).jointName;
if (jointName != headJointName && jointName != "Head") {
- _attachmentModels.at(i)->render(1.0f, renderMode, args);
+ _attachmentModels.at(i)->render(args, 1.0f);
}
}
+ */
}
//Renders sixense laser pointers for UI selection with controllers
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 4746a40099..c8d16e8cb0 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -37,9 +37,9 @@ public:
void simulate(float deltaTime);
void updateFromTrackers(float deltaTime);
- void render(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode = RenderArgs::NORMAL_RENDER_MODE, bool postLighting = false);
- void renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode renderMode, bool postLighting, float glowLevel = 0.0f);
- bool shouldRenderHead(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode) const;
+ virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting = false) override;
+ virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f) override;
+ virtual bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const override;
void renderDebugBodyPoints();
// setters
@@ -108,7 +108,7 @@ public:
Q_INVOKABLE glm::vec3 getEyePosition() const { return getHead()->getEyePosition(); }
Q_INVOKABLE glm::vec3 getTargetAvatarPosition() const { return _targetAvatarPosition; }
- QWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
+ AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
void updateLookAtTargetAvatar();
void clearLookAtTargetAvatar();
@@ -198,7 +198,7 @@ signals:
void transformChanged();
protected:
- virtual void renderAttachments(RenderArgs::RenderMode renderMode, RenderArgs* args);
+ virtual void renderAttachments(RenderArgs* args);
private:
@@ -226,7 +226,7 @@ private:
DynamicCharacterController _characterController;
- QWeakPointer _lookAtTargetAvatar;
+ AvatarWeakPointer _lookAtTargetAvatar;
glm::vec3 _targetAvatarPosition;
bool _shouldRender;
bool _billboardValid;
diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp
index 116e0d8c57..e1046cd33e 100644
--- a/interface/src/avatar/SkeletonModel.cpp
+++ b/interface/src/avatar/SkeletonModel.cpp
@@ -255,9 +255,12 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
}
void SkeletonModel::updateJointState(int index) {
+ if (index > _jointStates.size()) {
+ return; // bail
+ }
JointState& state = _jointStates[index];
const FBXJoint& joint = state.getFBXJoint();
- if (joint.parentIndex != -1) {
+ if (joint.parentIndex != -1 && joint.parentIndex <= _jointStates.size()) {
const JointState& parentState = _jointStates.at(joint.parentIndex);
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (index == geometry.leanJointIndex) {
diff --git a/interface/src/devices/CameraToolBox.cpp b/interface/src/devices/CameraToolBox.cpp
index a1e00d7052..27cee5185b 100644
--- a/interface/src/devices/CameraToolBox.cpp
+++ b/interface/src/devices/CameraToolBox.cpp
@@ -76,10 +76,10 @@ void CameraToolBox::render(int x, int y, bool boxed) {
glEnable(GL_TEXTURE_2D);
if (!_enabledTexture) {
- _enabledTexture = DependencyManager::get()->getImageTexture(PathUtils::resourcesPath() + "images/face.svg");
+ _enabledTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face.svg");
}
if (!_mutedTexture) {
- _mutedTexture = DependencyManager::get()->getImageTexture(PathUtils::resourcesPath() + "images/face-mute.svg");
+ _mutedTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face-mute.svg");
}
const int MUTE_ICON_SIZE = 24;
diff --git a/interface/src/devices/MotionTracker.h b/interface/src/devices/MotionTracker.h
index 5dd3f1ca3f..edfd3ae991 100644
--- a/interface/src/devices/MotionTracker.h
+++ b/interface/src/devices/MotionTracker.h
@@ -14,7 +14,18 @@
#include "DeviceTracker.h"
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#endif
+
#include
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+
#include
#include
diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp
index 78fe4508f3..b5538dd125 100644
--- a/interface/src/devices/OculusManager.cpp
+++ b/interface/src/devices/OculusManager.cpp
@@ -465,7 +465,7 @@ void OculusManager::configureCamera(Camera& camera) {
}
//Displays everything for the oculus, frame timing must be active
-void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) {
+void OculusManager::display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera) {
#ifdef DEBUG
// Ensure the frame counter always increments by exactly 1
@@ -532,7 +532,7 @@ void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientati
//Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) {
- DependencyManager::get()->prepare();
+ DependencyManager::get()->prepare(renderArgs);
} else {
auto primaryFBO = DependencyManager::get()->getPrimaryFramebuffer();
glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFBO));
@@ -613,7 +613,8 @@ void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientati
glViewport(vp.Pos.x, vp.Pos.y, vp.Size.w, vp.Size.h);
- qApp->displaySide(*_camera, false, RenderArgs::MONO);
+ renderArgs->_renderSide = RenderArgs::MONO;
+ qApp->displaySide(renderArgs, *_camera, false);
qApp->getApplicationOverlay().displayOverlayTextureHmd(*_camera);
});
_activeEye = ovrEye_Count;
@@ -625,7 +626,7 @@ void OculusManager::display(QGLWidget * glCanvas, const glm::quat &bodyOrientati
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) {
//Full texture viewport for glow effect
glViewport(0, 0, _renderTargetSize.w, _renderTargetSize.h);
- finalFbo = DependencyManager::get()->render();
+ finalFbo = DependencyManager::get()->render(renderArgs);
} else {
finalFbo = DependencyManager::get()->getPrimaryFramebuffer();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
diff --git a/interface/src/devices/OculusManager.h b/interface/src/devices/OculusManager.h
index 79b86e1a93..d65c31335b 100644
--- a/interface/src/devices/OculusManager.h
+++ b/interface/src/devices/OculusManager.h
@@ -21,6 +21,8 @@
#include
#include
+#include "RenderArgs.h"
+
class Camera;
class PalmData;
class Text3DOverlay;
@@ -62,7 +64,7 @@ public:
static void endFrameTiming();
static bool allowSwap();
static void configureCamera(Camera& camera);
- static void display(QGLWidget * glCanvas, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera);
+ static void display(QGLWidget * glCanvas, RenderArgs* renderArgs, const glm::quat &bodyOrientation, const glm::vec3 &position, Camera& whichCamera);
static void reset();
/// param \yaw[out] yaw in radians
diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp
index f2de97856e..a1e58fa8dc 100644
--- a/interface/src/devices/TV3DManager.cpp
+++ b/interface/src/devices/TV3DManager.cpp
@@ -82,7 +82,7 @@ void TV3DManager::configureCamera(Camera& whichCamera_, int screenWidth, int scr
glLoadIdentity();
}
-void TV3DManager::display(Camera& whichCamera) {
+void TV3DManager::display(RenderArgs* renderArgs, Camera& whichCamera) {
double nearZ = DEFAULT_NEAR_CLIP; // near clipping plane
double farZ = DEFAULT_FAR_CLIP; // far clipping plane
@@ -95,7 +95,7 @@ void TV3DManager::display(Camera& whichCamera) {
int portalH = deviceSize.height();
- DependencyManager::get()->prepare();
+ DependencyManager::get()->prepare(renderArgs);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Camera eyeCamera;
@@ -120,10 +120,9 @@ void TV3DManager::display(Camera& whichCamera) {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
- qApp->displaySide(eyeCamera, false);
-#if 0
+ renderArgs->_renderSide = RenderArgs::MONO;
+ qApp->displaySide(renderArgs, eyeCamera, false);
qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov);
-#endif
_activeEye = NULL;
}, [&]{
// render right side view
@@ -132,7 +131,7 @@ void TV3DManager::display(Camera& whichCamera) {
glPopMatrix();
glDisable(GL_SCISSOR_TEST);
- auto finalFbo = DependencyManager::get()->render();
+ auto finalFbo = DependencyManager::get()->render(renderArgs);
auto fboSize = finalFbo->getSize();
// Get the ACTUAL device size for the BLIT
deviceSize = qApp->getDeviceSize();
diff --git a/interface/src/devices/TV3DManager.h b/interface/src/devices/TV3DManager.h
index 63bc319d83..1a63161b1e 100644
--- a/interface/src/devices/TV3DManager.h
+++ b/interface/src/devices/TV3DManager.h
@@ -32,7 +32,7 @@ public:
static void connect();
static bool isConnected();
static void configureCamera(Camera& camera, int screenWidth, int screenHeight);
- static void display(Camera& whichCamera);
+ static void display(RenderArgs* renderArgs, Camera& whichCamera);
static void overrideOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane);
private:
diff --git a/interface/src/octree/OctreeFade.cpp b/interface/src/octree/OctreeFade.cpp
index ad313bdb6d..881f3c5938 100644
--- a/interface/src/octree/OctreeFade.cpp
+++ b/interface/src/octree/OctreeFade.cpp
@@ -37,8 +37,8 @@ OctreeFade::OctreeFade(FadeDirection direction, float red, float green, float bl
opacity = (direction == FADE_OUT) ? FADE_OUT_START : FADE_IN_START;
}
-void OctreeFade::render() {
- DependencyManager::get()->begin();
+void OctreeFade::render(RenderArgs* renderArgs) {
+ DependencyManager::get()->begin(renderArgs);
glDisable(GL_LIGHTING);
glPushMatrix();
@@ -53,7 +53,7 @@ void OctreeFade::render() {
glEnable(GL_LIGHTING);
- DependencyManager::get()->end();
+ DependencyManager::get()->end(renderArgs);
opacity *= (direction == FADE_OUT) ? FADE_OUT_STEP : FADE_IN_STEP;
}
diff --git a/interface/src/octree/OctreeFade.h b/interface/src/octree/OctreeFade.h
index daae9be66f..137a505537 100644
--- a/interface/src/octree/OctreeFade.h
+++ b/interface/src/octree/OctreeFade.h
@@ -39,7 +39,7 @@ public:
OctreeFade(FadeDirection direction = FADE_OUT, float red = DEFAULT_RED,
float green = DEFAULT_GREEN, float blue = DEFAULT_BLUE);
- void render();
+ void render(RenderArgs* renderArgs);
bool isDone() const;
};
diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp
index 38581b4fa9..8c6f6aa72e 100644
--- a/interface/src/ui/ApplicationOverlay.cpp
+++ b/interface/src/ui/ApplicationOverlay.cpp
@@ -189,7 +189,7 @@ GLuint ApplicationOverlay::getOverlayTexture() {
}
// Renders the overlays either to a texture or to the screen
-void ApplicationOverlay::renderOverlay() {
+void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
Overlays& overlays = qApp->getOverlays();
@@ -228,7 +228,7 @@ void ApplicationOverlay::renderOverlay() {
// give external parties a change to hook in
emit qApp->renderingOverlay();
- overlays.renderHUD();
+ overlays.renderHUD(renderArgs);
renderPointers();
@@ -297,9 +297,8 @@ void ApplicationOverlay::displayOverlayTexture() {
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
- if (_alpha < 1.0) {
- glEnable(GL_BLEND);
- }
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glViewport(0, 0, qApp->getDeviceSize().width(), qApp->getDeviceSize().height());
static const glm::vec2 topLeft(-1, 1);
@@ -307,9 +306,38 @@ void ApplicationOverlay::displayOverlayTexture() {
static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
- DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
+ DependencyManager::get()->renderQuad(
+ topLeft, bottomRight,
+ texCoordTopLeft, texCoordBottomRight,
glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
});
+
+ if (!_crosshairTexture) {
+ _crosshairTexture = DependencyManager::get()->
+ getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
+ }
+
+ //draw the mouse pointer
+ glm::vec2 canvasSize = qApp->getCanvasSize();
+ glm::vec2 mouseSize = 32.0f / canvasSize;
+ auto mouseTopLeft = topLeft * mouseSize;
+ auto mouseBottomRight = bottomRight * mouseSize;
+ vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY());
+ mousePosition /= canvasSize;
+ mousePosition *= 2.0f;
+ mousePosition -= 1.0f;
+ mousePosition.y *= -1.0f;
+
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
+ glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
+ DependencyManager::get()->renderQuad(
+ mouseTopLeft + mousePosition, mouseBottomRight + mousePosition,
+ texCoordTopLeft, texCoordBottomRight,
+ reticleColor);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
+ glDisable(GL_TEXTURE_2D);
} glPopMatrix();
}
@@ -454,11 +482,14 @@ void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float
});
if (!_crosshairTexture) {
- _crosshairTexture = DependencyManager::get()->
- getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
+ _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() +
+ "images/sixense-reticle.png");
}
//draw the mouse pointer
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
glm::vec2 canvasSize = qApp->getCanvasSize();
const float reticleSize = 40.0f / canvasSize.x * quadWidth;
@@ -592,11 +623,12 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position,
void ApplicationOverlay::renderPointers() {
//lazily load crosshair texture
if (_crosshairTexture == 0) {
- _crosshairTexture = DependencyManager::get()->
- getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
+ _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
}
glEnable(GL_TEXTURE_2D);
-
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
@@ -760,8 +792,14 @@ void ApplicationOverlay::renderControllerPointers() {
}
void ApplicationOverlay::renderPointersOculus() {
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_TEXTURE_2D);
+
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
glDisable(GL_DEPTH_TEST);
+
glMatrixMode(GL_MODELVIEW);
//Controller Pointers
@@ -786,6 +824,8 @@ void ApplicationOverlay::renderPointersOculus() {
}
glEnable(GL_DEPTH_TEST);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
}
//Renders a small magnification of the currently bound texture at the coordinates
diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h
index e40db9c326..6cd269dc26 100644
--- a/interface/src/ui/ApplicationOverlay.h
+++ b/interface/src/ui/ApplicationOverlay.h
@@ -35,9 +35,9 @@ public:
ApplicationOverlay();
~ApplicationOverlay();
- void renderOverlay();
+ void renderOverlay(RenderArgs* renderArgs);
GLuint getOverlayTexture();
-
+
QPoint getPalmClickLocation(const PalmData *palm) const;
bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp
index b452f153f0..196ba5d29e 100644
--- a/interface/src/ui/LoginDialog.cpp
+++ b/interface/src/ui/LoginDialog.cpp
@@ -1,6 +1,6 @@
//
-//
// LoginDialog.cpp
+// interface/src/ui
//
// Created by Bradley Austin Davis on 2015/04/14
// Copyright 2015 High Fidelity, Inc.
@@ -8,16 +8,22 @@
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+
#include "LoginDialog.h"
-#include "DependencyManager.h"
-#include "AccountManager.h"
-#include "Menu.h"
+#include
+
#include
+#include "AccountManager.h"
+#include "DependencyManager.h"
+#include "Menu.h"
+
HIFI_QML_DEF(LoginDialog)
-LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) {
+LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent),
+ _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString())
+{
connect(&AccountManager::getInstance(), &AccountManager::loginComplete,
this, &LoginDialog::handleLoginCompleted);
connect(&AccountManager::getInstance(), &AccountManager::loginFailed,
@@ -48,7 +54,7 @@ void LoginDialog::handleLoginCompleted(const QUrl&) {
}
void LoginDialog::handleLoginFailed() {
- setStatusText("Invalid username or password.< / font>");
+ setStatusText("Invalid username or password");
}
void LoginDialog::setStatusText(const QString& statusText) {
@@ -68,10 +74,11 @@ QString LoginDialog::rootUrl() const {
void LoginDialog::login(const QString& username, const QString& password) {
qDebug() << "Attempting to login " << username;
- setStatusText("Authenticating...");
+ setStatusText("Logging in...");
AccountManager::getInstance().requestAccessToken(username, password);
}
void LoginDialog::openUrl(const QString& url) {
qDebug() << url;
+ QDesktopServices::openUrl(url);
}
diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h
index e9ae0a1c16..50c820aa07 100644
--- a/interface/src/ui/LoginDialog.h
+++ b/interface/src/ui/LoginDialog.h
@@ -1,5 +1,6 @@
//
// LoginDialog.h
+// interface/src/ui
//
// Created by Bradley Austin Davis on 2015/04/14
// Copyright 2015 High Fidelity, Inc.
@@ -9,6 +10,7 @@
//
#pragma once
+
#ifndef hifi_LoginDialog_h
#define hifi_LoginDialog_h
diff --git a/interface/src/ui/RearMirrorTools.cpp b/interface/src/ui/RearMirrorTools.cpp
index ec73668d9e..33f3e1b487 100644
--- a/interface/src/ui/RearMirrorTools.cpp
+++ b/interface/src/ui/RearMirrorTools.cpp
@@ -34,11 +34,10 @@ RearMirrorTools::RearMirrorTools(QRect& bounds) :
_windowed(false),
_fullScreen(false)
{
- auto textureCache = DependencyManager::get();
- _closeTexture = textureCache->getImageTexture(PathUtils::resourcesPath() + "images/close.svg");
+ _closeTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/close.svg");
- _zoomHeadTexture = textureCache->getImageTexture(PathUtils::resourcesPath() + "images/plus.svg");
- _zoomBodyTexture = textureCache->getImageTexture(PathUtils::resourcesPath() + "images/minus.svg");
+ _zoomHeadTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/plus.svg");
+ _zoomBodyTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/minus.svg");
_shrinkIconRect = QRect(ICON_PADDING, ICON_PADDING, ICON_SIZE, ICON_SIZE);
_closeIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.top() + ICON_PADDING, ICON_SIZE, ICON_SIZE);
@@ -47,7 +46,7 @@ RearMirrorTools::RearMirrorTools(QRect& bounds) :
_headZoomIconRect = QRect(_bounds.left() + ICON_PADDING, _bounds.bottom() - ICON_PADDING - ICON_SIZE, ICON_SIZE, ICON_SIZE);
}
-void RearMirrorTools::render(bool fullScreen, const QPoint & mousePosition) {
+void RearMirrorTools::render(RenderArgs* renderArgs, bool fullScreen, const QPoint & mousePosition) {
if (fullScreen) {
_fullScreen = true;
displayIcon(QRect(QPoint(), qApp->getDeviceSize()), _shrinkIconRect, _closeTexture);
diff --git a/interface/src/ui/RearMirrorTools.h b/interface/src/ui/RearMirrorTools.h
index 2b359c2d07..c633d72a49 100644
--- a/interface/src/ui/RearMirrorTools.h
+++ b/interface/src/ui/RearMirrorTools.h
@@ -24,7 +24,7 @@ class RearMirrorTools : public QObject {
Q_OBJECT
public:
RearMirrorTools(QRect& bounds);
- void render(bool fullScreen, const QPoint & mousePos);
+ void render(RenderArgs* renderArgs, bool fullScreen, const QPoint & mousePos);
bool mousePressEvent(int x, int y);
static Setting::Handle rearViewZoomLevel;
diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp
index c49208c835..32df75c46d 100644
--- a/interface/src/ui/Stats.cpp
+++ b/interface/src/ui/Stats.cpp
@@ -467,31 +467,30 @@ void Stats::display(
horizontalOffset += 5;
// Model/Entity render details
- EntityTreeRenderer* entities = Application::getInstance()->getEntities();
octreeStats.str("");
- octreeStats << "Entity Items rendered: " << entities->getItemsRendered()
- << " / Out of view:" << entities->getItemsOutOfView()
- << " / Too small:" << entities->getItemsTooSmall();
+ octreeStats << "Triangles: " << _renderDetails._trianglesRendered
+ << " / Quads:" << _renderDetails._quadsRendered
+ << " / Material Switches:" << _renderDetails._materialSwitches;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
if (_expanded) {
octreeStats.str("");
- octreeStats << " Meshes rendered: " << entities->getMeshesRendered()
- << " / Out of view:" << entities->getMeshesOutOfView()
- << " / Too small:" << entities->getMeshesTooSmall();
+ octreeStats << " Mesh Parts Rendered Opaque: " << _renderDetails._opaque._rendered
+ << " / Translucent:" << _renderDetails._translucent._rendered;
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
-
+
octreeStats.str("");
- octreeStats << " Triangles: " << entities->getTrianglesRendered()
- << " / Quads:" << entities->getQuadsRendered()
- << " / Material Switches:" << entities->getMaterialSwitches();
+ octreeStats << " Opaque considered: " << _renderDetails._opaque._considered
+ << " / Out of view:" << _renderDetails._opaque._outOfView
+ << " / Too small:" << _renderDetails._opaque._tooSmall;
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
-
+
octreeStats.str("");
- octreeStats << " Mesh Parts Rendered Opaque: " << entities->getOpaqueMeshPartsRendered()
- << " / Translucent:" << entities->getTranslucentMeshPartsRendered();
+ octreeStats << " Translucent considered: " << _renderDetails._translucent._considered
+ << " / Out of view:" << _renderDetails._translucent._outOfView
+ << " / Too small:" << _renderDetails._translucent._tooSmall;
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
}
diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h
index 00c1650b71..4c6d6ede4e 100644
--- a/interface/src/ui/Stats.h
+++ b/interface/src/ui/Stats.h
@@ -14,7 +14,7 @@
#include
-#include
+#include
class Stats: public QObject {
Q_OBJECT
@@ -35,6 +35,8 @@ public:
int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess);
bool includeTimingRecord(const QString& name);
+ void setRenderDetails(const RenderDetails& details) { _renderDetails = details; }
+
private:
static Stats* _sharedInstance;
@@ -51,6 +53,7 @@ private:
int _lastHorizontalOffset;
+ RenderDetails _renderDetails;
};
#endif // hifi_Stats_h
diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp
index f0c49979c8..db252d8a04 100644
--- a/interface/src/ui/overlays/Base3DOverlay.cpp
+++ b/interface/src/ui/overlays/Base3DOverlay.cpp
@@ -49,6 +49,11 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) :
Base3DOverlay::~Base3DOverlay() {
}
+// TODO: Implement accurate getBounds() implementations
+AABox Base3DOverlay::getBounds() const {
+ return AABox(_position, glm::vec3(1.0f));
+}
+
void Base3DOverlay::setProperties(const QScriptValue& properties) {
Overlay::setProperties(properties);
diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h
index bbf850da8e..b24908a0cc 100644
--- a/interface/src/ui/overlays/Base3DOverlay.h
+++ b/interface/src/ui/overlays/Base3DOverlay.h
@@ -49,6 +49,8 @@ public:
void setDrawInFront(bool value) { _drawInFront = value; }
void setDrawOnHUD(bool value) { _drawOnHUD = value; }
+ virtual AABox getBounds() const;
+
virtual void setProperties(const QScriptValue& properties);
virtual QScriptValue getProperty(const QString& property);
diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp
index 60f985b083..6fc9fe6e27 100644
--- a/interface/src/ui/overlays/Cube3DOverlay.cpp
+++ b/interface/src/ui/overlays/Cube3DOverlay.cpp
@@ -126,7 +126,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
} else {
glScalef(dimensions.x, dimensions.y, dimensions.z);
- DependencyManager::get()->renderWireCube(1.0f, cubeColor);
+ DependencyManager::get()->renderWireCube(1.0f, cubeColor);
}
}
glPopMatrix();
diff --git a/interface/src/ui/overlays/LocalModelsOverlay.cpp b/interface/src/ui/overlays/LocalModelsOverlay.cpp
index 7390ea4310..e5c8e6076d 100644
--- a/interface/src/ui/overlays/LocalModelsOverlay.cpp
+++ b/interface/src/ui/overlays/LocalModelsOverlay.cpp
@@ -45,10 +45,10 @@ void LocalModelsOverlay::render(RenderArgs* args) {
glPushMatrix(); {
Application* app = Application::getInstance();
- Transform originalTransform = qApp->getViewTransform();
- qApp->getViewTransform().postTranslate(_position);
- _entityTreeRenderer->render();
- qApp->setViewTransform(originalTransform);
+ glm::vec3 oldTranslation = app->getViewMatrixTranslation();
+ app->setViewMatrixTranslation(oldTranslation + _position);
+ _entityTreeRenderer->render(args);
+ Application::getInstance()->setViewMatrixTranslation(oldTranslation);
} glPopMatrix();
}
}
diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp
index 749dba9ea8..822fff9808 100644
--- a/interface/src/ui/overlays/ModelOverlay.cpp
+++ b/interface/src/ui/overlays/ModelOverlay.cpp
@@ -9,6 +9,7 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+#include
#include
#include "ModelOverlay.h"
@@ -54,11 +55,34 @@ void ModelOverlay::update(float deltatime) {
_isLoaded = _model.isActive();
}
+bool ModelOverlay::addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) {
+ Base3DOverlay::addToScene(overlay, scene, pendingChanges);
+ _model.addToScene(scene, pendingChanges);
+ return true;
+}
+
+void ModelOverlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) {
+ Base3DOverlay::removeFromScene(overlay, scene, pendingChanges);
+ _model.removeFromScene(scene, pendingChanges);
+}
+
void ModelOverlay::render(RenderArgs* args) {
+
+ // check to see if when we added our model to the scene they were ready, if they were not ready, then
+ // fix them up in the scene
+ render::ScenePointer scene = Application::getInstance()->getMain3DScene();
+ render::PendingChanges pendingChanges;
+ if (_model.needsFixupInScene()) {
+ _model.removeFromScene(scene, pendingChanges);
+ _model.addToScene(scene, pendingChanges);
+ }
+ scene->enqueuePendingChanges(pendingChanges);
+
if (!_visible) {
return;
}
-
+
+ /*
if (_model.isActive()) {
if (_model.isRenderable()) {
float glowLevel = getGlowLevel();
@@ -66,12 +90,13 @@ void ModelOverlay::render(RenderArgs* args) {
if (glowLevel > 0.0f) {
glower = new Glower(glowLevel);
}
- _model.render(getAlpha(), RenderArgs::DEFAULT_RENDER_MODE, args);
+ _model.render(args, getAlpha());
if (glower) {
delete glower;
}
}
}
+ */
}
void ModelOverlay::setProperties(const QScriptValue &properties) {
diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h
index 8cd095f778..a81cae530a 100644
--- a/interface/src/ui/overlays/ModelOverlay.h
+++ b/interface/src/ui/overlays/ModelOverlay.h
@@ -32,6 +32,9 @@ public:
virtual ModelOverlay* createClone() const;
+ virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges);
+ virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges);
+
private:
Model _model;
diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp
index 024a94e950..745c2b4a10 100644
--- a/interface/src/ui/overlays/Overlay.cpp
+++ b/interface/src/ui/overlays/Overlay.cpp
@@ -16,6 +16,7 @@
#include
Overlay::Overlay() :
+ _renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(true),
_alpha(DEFAULT_ALPHA),
_glowLevel(0.0f),
@@ -35,6 +36,7 @@ Overlay::Overlay() :
}
Overlay::Overlay(const Overlay* overlay) :
+ _renderItemID(render::Item::INVALID_ITEM_ID),
_isLoaded(overlay->_isLoaded),
_alpha(overlay->_alpha),
_glowLevel(overlay->_glowLevel),
@@ -225,3 +227,16 @@ float Overlay::updatePulse() {
return _pulse;
}
+
+bool Overlay::addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) {
+ auto overlayPayload = new Overlay::Payload(overlay);
+ auto overlayPayloadPointer = Overlay::PayloadPointer(overlayPayload);
+ _renderItemID = scene->allocateID();
+ pendingChanges.resetItem(_renderItemID, overlayPayloadPointer);
+ return true;
+}
+
+void Overlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges) {
+ pendingChanges.removeItem(_renderItemID);
+}
+
diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h
index 9077605fc4..1a808bc15c 100644
--- a/interface/src/ui/overlays/Overlay.h
+++ b/interface/src/ui/overlays/Overlay.h
@@ -21,6 +21,8 @@
#include
#include // for xColor
#include
+#include
+#include
const xColor DEFAULT_OVERLAY_COLOR = { 255, 255, 255 };
const float DEFAULT_ALPHA = 0.7f;
@@ -33,7 +35,12 @@ public:
NO_ANCHOR,
MY_AVATAR
};
-
+
+ typedef std::shared_ptr Pointer;
+
+ typedef render::Payload Payload;
+ typedef std::shared_ptr PayloadPointer;
+
Overlay();
Overlay(const Overlay* overlay);
~Overlay();
@@ -41,6 +48,9 @@ public:
virtual void update(float deltatime) {}
virtual void render(RenderArgs* args) = 0;
+ virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges);
+ virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges);
+
// getters
virtual bool is3D() const = 0;
bool isLoaded() { return _isLoaded; }
@@ -50,7 +60,6 @@ public:
float getGlowLevel();
Anchor getAnchor() const { return _anchor; }
-
float getPulseMax() const { return _pulseMax; }
float getPulseMin() const { return _pulseMin; }
float getPulsePeriod() const { return _pulsePeriod; }
@@ -81,9 +90,14 @@ public:
virtual Overlay* createClone() const = 0;
virtual QScriptValue getProperty(const QString& property);
+ render::ItemID getRenderItemID() const { return _renderItemID; }
+ void setRenderItemID(render::ItemID renderItemID) { _renderItemID = renderItemID; }
+
protected:
float updatePulse();
+ render::ItemID _renderItemID;
+
bool _isLoaded;
float _alpha;
float _glowLevel;
@@ -106,5 +120,11 @@ protected:
QScriptEngine* _scriptEngine;
};
+namespace render {
+ template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay);
+ template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay);
+ template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
+}
+
#endif // hifi_Overlay_h
diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp
index 0537c62b38..6e579ed4c4 100644
--- a/interface/src/ui/overlays/Overlays.cpp
+++ b/interface/src/ui/overlays/Overlays.cpp
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include "BillboardOverlay.h"
#include "Circle3DOverlay.h"
@@ -31,6 +32,7 @@
#include "TextOverlay.h"
#include "Text3DOverlay.h"
+
Overlays::Overlays() : _nextOverlayID(1) {
}
@@ -38,23 +40,18 @@ Overlays::~Overlays() {
{
QWriteLocker lock(&_lock);
- foreach(Overlay* thisOverlay, _overlaysHUD) {
- delete thisOverlay;
+ QWriteLocker deleteLock(&_deleteLock);
+ foreach(Overlay::Pointer overlay, _overlaysHUD) {
+ _overlaysToDelete.push_back(overlay);
+ }
+ foreach(Overlay::Pointer overlay, _overlaysWorld) {
+ _overlaysToDelete.push_back(overlay);
}
_overlaysHUD.clear();
- foreach(Overlay* thisOverlay, _overlaysWorld) {
- delete thisOverlay;
- }
_overlaysWorld.clear();
}
- if (!_overlaysToDelete.isEmpty()) {
- QWriteLocker lock(&_deleteLock);
- do {
- delete _overlaysToDelete.takeLast();
- } while (!_overlaysToDelete.isEmpty());
- }
-
+ cleanupOverlaysToDelete();
}
void Overlays::init() {
@@ -65,100 +62,61 @@ void Overlays::update(float deltatime) {
{
QWriteLocker lock(&_lock);
- foreach(Overlay* thisOverlay, _overlaysHUD) {
+ foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
thisOverlay->update(deltatime);
}
- foreach(Overlay* thisOverlay, _overlaysWorld) {
+ foreach(Overlay::Pointer thisOverlay, _overlaysWorld) {
thisOverlay->update(deltatime);
}
}
- if (!_overlaysToDelete.isEmpty()) {
- QWriteLocker lock(&_deleteLock);
- do {
- delete _overlaysToDelete.takeLast();
- } while (!_overlaysToDelete.isEmpty());
- }
-
+ cleanupOverlaysToDelete();
}
-void Overlays::renderHUD() {
+void Overlays::cleanupOverlaysToDelete() {
+ if (!_overlaysToDelete.isEmpty()) {
+ render::ScenePointer scene = Application::getInstance()->getMain3DScene();
+ render::PendingChanges pendingChanges;
+
+ {
+ QWriteLocker lock(&_deleteLock);
+
+ do {
+ Overlay::Pointer overlay = _overlaysToDelete.takeLast();
+
+ auto itemID = overlay->getRenderItemID();
+ if (itemID != render::Item::INVALID_ITEM_ID) {
+ overlay->removeFromScene(overlay, scene, pendingChanges);
+ }
+ } while (!_overlaysToDelete.isEmpty());
+ }
+
+ if (pendingChanges._removedItems.size() > 0) {
+ scene->enqueuePendingChanges(pendingChanges);
+ }
+ }
+}
+
+void Overlays::renderHUD(RenderArgs* renderArgs) {
QReadLocker lock(&_lock);
auto lodManager = DependencyManager::get();
- RenderArgs args(NULL, Application::getInstance()->getViewFrustum(),
- lodManager->getOctreeSizeScale(),
- lodManager->getBoundaryLevelAdjust(),
- RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
- foreach(Overlay* thisOverlay, _overlaysHUD) {
+ foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
if (thisOverlay->is3D()) {
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
- thisOverlay->render(&args);
+ thisOverlay->render(renderArgs);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
- } else{
- thisOverlay->render(&args);
+ } else {
+ thisOverlay->render(renderArgs);
}
}
}
-void Overlays::renderWorld(bool drawFront,
- RenderArgs::RenderMode renderMode,
- RenderArgs::RenderSide renderSide,
- RenderArgs::DebugFlags renderDebugFlags) {
- QReadLocker lock(&_lock);
- if (_overlaysWorld.size() == 0) {
- return;
- }
- bool myAvatarComputed = false;
- MyAvatar* avatar = DependencyManager::get()->getMyAvatar();
- glm::quat myAvatarRotation;
- glm::vec3 myAvatarPosition(0.0f);
- float angle = 0.0f;
- glm::vec3 axis(0.0f, 1.0f, 0.0f);
- float myAvatarScale = 1.0f;
-
- auto lodManager = DependencyManager::get