mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge branch 'master' into 20551
This commit is contained in:
commit
cb6aef16e6
168 changed files with 6355 additions and 2731 deletions
23
examples/dialTone.js
Normal file
23
examples/dialTone.js
Normal file
|
@ -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);
|
||||
});
|
89
examples/example/dynamicLandscape.js
Normal file
89
examples/example/dynamicLandscape.js
Normal file
|
@ -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)
|
||||
|
||||
|
488
examples/grab.js
488
examples/grab.js
|
@ -1,4 +1,3 @@
|
|||
|
||||
// grab.js
|
||||
// examples
|
||||
//
|
||||
|
@ -11,248 +10,337 @@
|
|||
// 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}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||
Script.update.connect(update);
|
||||
|
|
|
@ -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 = [{
|
||||
|
|
56
examples/utilities.js
Normal file
56
examples/utilities.js
Normal file
|
@ -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));
|
||||
}
|
|
@ -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); };
|
||||
|
|
104
examples/utilities/tools/renderEngineDebug.js
Executable file
104
examples/utilities/tools/renderEngineDebug.js
Executable file
|
@ -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);
|
|
@ -138,7 +138,7 @@ target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
|||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
# 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)
|
||||
|
||||
|
|
BIN
interface/resources/sounds/short1.wav
Normal file
BIN
interface/resources/sounds/short1.wav
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -77,6 +77,7 @@
|
|||
#include "octree/OctreePacketProcessor.h"
|
||||
#include "UndoStackScriptingInterface.h"
|
||||
|
||||
#include "render/Engine.h"
|
||||
|
||||
class QGLWidget;
|
||||
class QKeyEvent;
|
||||
|
@ -209,7 +210,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; }
|
||||
|
@ -268,9 +268,9 @@ public:
|
|||
virtual void setupWorldLight();
|
||||
virtual bool shouldRenderMesh(float largestDimension, float distanceToCamera);
|
||||
|
||||
QImage renderAvatarBillboard();
|
||||
QImage renderAvatarBillboard(RenderArgs* renderArgs);
|
||||
|
||||
void displaySide(Camera& whichCamera, bool selfAvatarOnly = false, bool billboard = false, RenderArgs::RenderSide renderSide = RenderArgs::MONO);
|
||||
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.
|
||||
|
@ -347,6 +347,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:
|
||||
|
||||
|
@ -499,8 +504,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);
|
||||
|
@ -529,7 +534,6 @@ private:
|
|||
QElapsedTimer _timerStart;
|
||||
QElapsedTimer _lastTimeUpdated;
|
||||
bool _justStarted;
|
||||
Stars _stars;
|
||||
|
||||
ShapeManager _shapeManager;
|
||||
PhysicalEntitySimulation _entitySimulation;
|
||||
|
@ -631,9 +635,6 @@ private:
|
|||
|
||||
TouchEvent _lastTouchEvent;
|
||||
|
||||
Overlays _overlays;
|
||||
ApplicationOverlay _applicationOverlay;
|
||||
|
||||
RunningScriptsWidget* _runningScriptsWidget;
|
||||
QHash<QString, ScriptEngine*> _scriptEnginesHash;
|
||||
bool _runningScriptsWidgetWasVisible;
|
||||
|
@ -670,6 +671,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
|
||||
|
|
|
@ -68,7 +68,7 @@ void Environment::resetToDefault() {
|
|||
_data[HifiSockAddr()][0];
|
||||
}
|
||||
|
||||
void Environment::renderAtmospheres(Camera& camera) {
|
||||
void Environment::renderAtmospheres(ViewFrustum& camera) {
|
||||
// get the lock for the duration of the call
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
|
@ -228,7 +228,7 @@ ProgramObject* Environment::createSkyProgram(const char* from, int* locations) {
|
|||
return program;
|
||||
}
|
||||
|
||||
void Environment::renderAtmosphere(Camera& camera, const EnvironmentData& data) {
|
||||
void Environment::renderAtmosphere(ViewFrustum& camera, const EnvironmentData& data) {
|
||||
glm::vec3 center = data.getAtmosphereCenter();
|
||||
|
||||
glPushMatrix();
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "EnvironmentData.h"
|
||||
|
||||
class Camera;
|
||||
class ViewFrustum;
|
||||
class ProgramObject;
|
||||
|
||||
class Environment {
|
||||
|
@ -29,7 +29,7 @@ public:
|
|||
|
||||
void init();
|
||||
void resetToDefault();
|
||||
void renderAtmospheres(Camera& camera);
|
||||
void renderAtmospheres(ViewFrustum& camera);
|
||||
|
||||
void override(const EnvironmentData& overrideData) { _overrideData = overrideData; _environmentIsOverridden = true; }
|
||||
void endOverride() { _environmentIsOverridden = false; }
|
||||
|
@ -46,7 +46,7 @@ private:
|
|||
|
||||
ProgramObject* createSkyProgram(const char* from, int* locations);
|
||||
|
||||
void renderAtmosphere(Camera& camera, const EnvironmentData& data);
|
||||
void renderAtmosphere(ViewFrustum& camera, const EnvironmentData& data);
|
||||
|
||||
bool _initialized;
|
||||
ProgramObject* _skyFromAtmosphereProgram;
|
||||
|
|
|
@ -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<float, float> 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<float, float>::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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -33,45 +33,44 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
void renderWorldBox() {
|
||||
void renderWorldBox(gpu::Batch& batch) {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
||||
// 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
|
||||
|
|
|
@ -16,10 +16,12 @@
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <QSettings>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
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,
|
||||
|
|
|
@ -40,13 +40,13 @@ void AudioToolBox::render(int x, int y, int padding, bool boxed) {
|
|||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
if (!_micTexture) {
|
||||
_micTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/mic.svg");
|
||||
_micTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic.svg");
|
||||
}
|
||||
if (!_muteTexture) {
|
||||
_muteTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/mic-mute.svg");
|
||||
_muteTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/mic-mute.svg");
|
||||
}
|
||||
if (_boxTexture) {
|
||||
_boxTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/audio-box.svg");
|
||||
_boxTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/audio-box.svg");
|
||||
}
|
||||
|
||||
auto audioIO = DependencyManager::get<AudioClient>();
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <TextRenderer.h>
|
||||
#include <TextRenderer3D.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
#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*>(avatar.get())->getBounds();
|
||||
}
|
||||
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) {
|
||||
Avatar* avatarPtr = static_cast<Avatar*>(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<LODManager>()->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,28 @@ 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<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
auto avatarPayload = new render::Payload<AvatarData>(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<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_renderItemID);
|
||||
_skeletonModel.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<AvatarManager>()->getMyAvatar()->getPosition(), _position) < 10.0f) {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
|
@ -299,15 +338,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 +360,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 +372,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 +398,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 +429,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 +441,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<GeometryCache>()->renderSphere(LOOK_AT_INDICATOR_RADIUS, 15, 15, LOOK_AT_INDICATOR_COLOR);
|
||||
glPopMatrix();
|
||||
Transform transform;
|
||||
transform.setTranslation(position);
|
||||
batch->setModelTransform(transform);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(*batch, LOOK_AT_INDICATOR_RADIUS, 15, 15, LOOK_AT_INDICATOR_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -437,31 +471,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<GeometryCache>()->allocateID();
|
||||
}
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(sphereRadius, 15, 15,
|
||||
|
||||
DependencyManager::get<GeometryCache>()->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 +516,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 +577,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 +604,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<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
|
||||
gpu::Batch& batch = *renderArgs->_batch;
|
||||
batch.setUniformTexture(0, _billboardTexture->getGPUTexture());
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, true);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glEnable(GL_LIGHTING);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
float Avatar::getBillboardSize() const {
|
||||
|
@ -654,9 +689,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<AvatarManager>()->shouldShowReceiveStats();
|
||||
bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar();
|
||||
|
||||
if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) {
|
||||
return;
|
||||
|
@ -665,31 +701,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 +723,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<GeometryCache>()->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<DeferredLightingEffect>()->bindSimpleProgram(*batch);
|
||||
DependencyManager::get<GeometryCache>()->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 +1064,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,12 +20,20 @@
|
|||
#include <AvatarData.h>
|
||||
#include <ShapeInfo.h>
|
||||
|
||||
#include <render/Scene.h>
|
||||
|
||||
#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<AvatarData> Payload;
|
||||
typedef std::shared_ptr<render::Item::PayloadInterface> 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<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges);
|
||||
|
||||
void removeFromScene(AvatarSharedPointer self, std::shared_ptr<render::Scene> 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<Hand*>(_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;
|
||||
|
||||
|
|
|
@ -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<QWeakPointer<Node> >("NodeWeakPointer");
|
||||
_myAvatar = QSharedPointer<MyAvatar>(new MyAvatar());
|
||||
_myAvatar = std::shared_ptr<MyAvatar>(new MyAvatar());
|
||||
}
|
||||
|
||||
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,9 +97,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
// simulate avatars
|
||||
AvatarHash::iterator avatarIterator = _avatarHash.begin();
|
||||
while (avatarIterator != _avatarHash.end()) {
|
||||
Avatar* avatar = reinterpret_cast<Avatar*>(avatarIterator.value().data());
|
||||
Avatar* avatar = reinterpret_cast<Avatar*>(avatarIterator.value().get());
|
||||
|
||||
if (avatar == _myAvatar || !avatar->isInitialized()) {
|
||||
if (avatar == _myAvatar.get() || !avatar->isInitialized()) {
|
||||
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
|
||||
// DO NOT update or fade out uninitialized Avatars
|
||||
++avatarIterator;
|
||||
|
@ -111,32 +116,6 @@ 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<SceneScriptingInterface>()->shouldRenderAvatars()) {
|
||||
foreach (const AvatarSharedPointer& avatarPointer, _avatarHash) {
|
||||
Avatar* avatar = static_cast<Avatar*>(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<AvatarSharedPointer>::iterator fadingIterator = _avatarFades.begin();
|
||||
|
||||
|
@ -144,7 +123,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
|
|||
const float MIN_FADE_SCALE = 0.001f;
|
||||
|
||||
while (fadingIterator != _avatarFades.end()) {
|
||||
Avatar* avatar = static_cast<Avatar*>(fadingIterator->data());
|
||||
Avatar* avatar = static_cast<Avatar*>(fadingIterator->get());
|
||||
avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true);
|
||||
if (avatar->getTargetScale() < MIN_FADE_SCALE) {
|
||||
fadingIterator = _avatarFades.erase(fadingIterator);
|
||||
|
@ -155,25 +134,17 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
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<Avatar*>(fadingAvatar.data());
|
||||
if (avatar != static_cast<Avatar*>(_myAvatar.data()) && avatar->isInitialized()) {
|
||||
avatar->render(cameraPosition, renderMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AvatarSharedPointer AvatarManager::newSharedAvatar() {
|
||||
return AvatarSharedPointer(new Avatar());
|
||||
}
|
||||
|
||||
// virtual
|
||||
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||
AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer);
|
||||
std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer));
|
||||
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
avatar->addToScene(avatar, scene, pendingChanges);
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
return avatar;
|
||||
}
|
||||
|
||||
|
@ -194,13 +165,16 @@ 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<Avatar*>(avatarIterator.value().data());
|
||||
std::shared_ptr<Avatar> avatar = std::dynamic_pointer_cast<Avatar>(avatarIterator.value());
|
||||
if (avatar != _myAvatar && avatar->isInitialized()) {
|
||||
removeAvatarMotionState(avatar);
|
||||
|
||||
removeAvatarMotionState(avatar.get());
|
||||
_avatarFades.push_back(avatarIterator.value());
|
||||
_avatarHash.erase(avatarIterator);
|
||||
}
|
||||
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
avatar->removeFromScene(avatar, scene, pendingChanges);
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,8 +182,8 @@ 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<Avatar*>(avatarIterator.value().data());
|
||||
if (avatar == _myAvatar || !avatar->isInitialized()) {
|
||||
Avatar* avatar = reinterpret_cast<Avatar*>(avatarIterator.value().get());
|
||||
if (avatar == _myAvatar.get() || !avatar->isInitialized()) {
|
||||
// don't remove myAvatar or uninitialized avatars from the list
|
||||
++avatarIterator;
|
||||
} else {
|
||||
|
@ -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<Avatar*>(avatarItr.value().data());
|
||||
Avatar* avatar = static_cast<Avatar*>(avatarItr.value().get());
|
||||
AvatarMotionState* motionState = avatar->_motionState;
|
||||
if (motionState) {
|
||||
motionState->addDirtyFlags(EntityItem::DIRTY_SHAPE);
|
||||
|
|
|
@ -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<AvatarSharedPointer> _avatarFades;
|
||||
QSharedPointer<MyAvatar> _myAvatar;
|
||||
std::shared_ptr<MyAvatar> _myAvatar;
|
||||
quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate.
|
||||
|
||||
QVector<AvatarManager::LocalLight> _localLights;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<GeometryCache>();
|
||||
DependencyManager::get<GlowEffect>()->begin();
|
||||
DependencyManager::get<GlowEffect>()->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<GlowEffect>()->end();
|
||||
DependencyManager::get<GlowEffect>()->end(renderArgs);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<AvatarManager>()->getAvatarHash()) {
|
||||
Avatar* avatar = static_cast<Avatar*>(avatarPointer.data());
|
||||
Avatar* avatar = static_cast<Avatar*>(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<Avatar*>(_lookAtTargetAvatar.data())->setIsLookAtTarget(true);
|
||||
auto avatarPointer = _lookAtTargetAvatar.lock();
|
||||
if (avatarPointer) {
|
||||
static_cast<Avatar*>(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
|
||||
|
|
|
@ -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<AvatarData> 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<AvatarData> _lookAtTargetAvatar;
|
||||
AvatarWeakPointer _lookAtTargetAvatar;
|
||||
glm::vec3 _targetAvatarPosition;
|
||||
bool _shouldRender;
|
||||
bool _billboardValid;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -76,10 +76,10 @@ void CameraToolBox::render(int x, int y, bool boxed) {
|
|||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
if (!_enabledTexture) {
|
||||
_enabledTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/face.svg");
|
||||
_enabledTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face.svg");
|
||||
}
|
||||
if (!_mutedTexture) {
|
||||
_mutedTexture = DependencyManager::get<TextureCache>()->getImageTexture(PathUtils::resourcesPath() + "images/face-mute.svg");
|
||||
_mutedTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/face-mute.svg");
|
||||
}
|
||||
|
||||
const int MUTE_ICON_SIZE = 24;
|
||||
|
|
|
@ -14,7 +14,18 @@
|
|||
|
||||
#include "DeviceTracker.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#endif
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
|
|
|
@ -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<GlowEffect>()->prepare();
|
||||
DependencyManager::get<GlowEffect>()->prepare(renderArgs);
|
||||
} else {
|
||||
auto primaryFBO = DependencyManager::get<TextureCache>()->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<GlowEffect>()->render();
|
||||
finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs);
|
||||
} else {
|
||||
finalFbo = DependencyManager::get<TextureCache>()->getPrimaryFramebuffer();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "RenderArgs.h"
|
||||
|
||||
class Camera;
|
||||
class PalmData;
|
||||
class Text3DOverlay;
|
||||
|
@ -61,7 +63,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
|
||||
|
|
|
@ -80,7 +80,7 @@ void TV3DManager::configureCamera(Camera& whichCamera, int screenWidth, int scre
|
|||
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
|
||||
|
||||
|
@ -93,7 +93,7 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
int portalH = deviceSize.height();
|
||||
|
||||
|
||||
DependencyManager::get<GlowEffect>()->prepare();
|
||||
DependencyManager::get<GlowEffect>()->prepare(renderArgs);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
Camera eyeCamera;
|
||||
|
@ -118,7 +118,8 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
qApp->displaySide(eyeCamera, false, RenderArgs::MONO);
|
||||
renderArgs->_renderSide = RenderArgs::MONO;
|
||||
qApp->displaySide(renderArgs, eyeCamera, false);
|
||||
qApp->getApplicationOverlay().displayOverlayTextureStereo(whichCamera, _aspect, fov);
|
||||
_activeEye = NULL;
|
||||
}, [&]{
|
||||
|
@ -128,7 +129,7 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
glPopMatrix();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
auto finalFbo = DependencyManager::get<GlowEffect>()->render();
|
||||
auto finalFbo = DependencyManager::get<GlowEffect>()->render(renderArgs);
|
||||
auto fboSize = finalFbo->getSize();
|
||||
// Get the ACTUAL device size for the BLIT
|
||||
deviceSize = qApp->getDeviceSize();
|
||||
|
|
|
@ -33,7 +33,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:
|
||||
|
|
|
@ -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<GlowEffect>()->begin();
|
||||
void OctreeFade::render(RenderArgs* renderArgs) {
|
||||
DependencyManager::get<GlowEffect>()->begin(renderArgs);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glPushMatrix();
|
||||
|
@ -53,7 +53,7 @@ void OctreeFade::render() {
|
|||
glEnable(GL_LIGHTING);
|
||||
|
||||
|
||||
DependencyManager::get<GlowEffect>()->end();
|
||||
DependencyManager::get<GlowEffect>()->end(renderArgs);
|
||||
|
||||
opacity *= (direction == FADE_OUT) ? FADE_OUT_STEP : FADE_IN_STEP;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ ApplicationOverlay::~ApplicationOverlay() {
|
|||
}
|
||||
|
||||
// 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();
|
||||
|
||||
|
@ -222,7 +222,7 @@ void ApplicationOverlay::renderOverlay() {
|
|||
// give external parties a change to hook in
|
||||
emit qApp->renderingOverlay();
|
||||
|
||||
overlays.renderHUD();
|
||||
overlays.renderHUD(renderArgs);
|
||||
|
||||
renderPointers();
|
||||
|
||||
|
@ -423,8 +423,8 @@ void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float
|
|||
});
|
||||
|
||||
if (!_crosshairTexture) {
|
||||
_crosshairTexture = DependencyManager::get<TextureCache>()->
|
||||
getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
|
||||
_crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() +
|
||||
"images/sixense-reticle.png");
|
||||
}
|
||||
|
||||
//draw the mouse pointer
|
||||
|
@ -554,8 +554,7 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position,
|
|||
void ApplicationOverlay::renderPointers() {
|
||||
//lazily load crosshair texture
|
||||
if (_crosshairTexture == 0) {
|
||||
_crosshairTexture = DependencyManager::get<TextureCache>()->
|
||||
getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
|
||||
_crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
|
||||
}
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
ApplicationOverlay();
|
||||
~ApplicationOverlay();
|
||||
|
||||
void renderOverlay();
|
||||
void renderOverlay(RenderArgs* renderArgs);
|
||||
void displayOverlayTexture();
|
||||
void displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov);
|
||||
void displayOverlayTextureHmd(Camera& whichCamera);
|
||||
|
|
|
@ -34,11 +34,10 @@ RearMirrorTools::RearMirrorTools(QRect& bounds) :
|
|||
_windowed(false),
|
||||
_fullScreen(false)
|
||||
{
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
_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);
|
||||
|
|
|
@ -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<int> rearViewZoomLevel;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <QObject>
|
||||
|
||||
#include <NodeList.h>
|
||||
#include <RenderArgs.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
|
||||
} else {
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(1.0f, cubeColor);
|
||||
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f, cubeColor);
|
||||
}
|
||||
}
|
||||
glPopMatrix();
|
||||
|
|
|
@ -47,7 +47,7 @@ void LocalModelsOverlay::render(RenderArgs* args) {
|
|||
Application* app = Application::getInstance();
|
||||
glm::vec3 oldTranslation = app->getViewMatrixTranslation();
|
||||
app->setViewMatrixTranslation(oldTranslation + _position);
|
||||
_entityTreeRenderer->render();
|
||||
_entityTreeRenderer->render(args);
|
||||
Application::getInstance()->setViewMatrixTranslation(oldTranslation);
|
||||
} glPopMatrix();
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <Application.h>
|
||||
#include <GlowEffect.h>
|
||||
|
||||
#include "ModelOverlay.h"
|
||||
|
@ -54,11 +55,34 @@ void ModelOverlay::update(float deltatime) {
|
|||
_isLoaded = _model.isActive();
|
||||
}
|
||||
|
||||
bool ModelOverlay::addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
Base3DOverlay::addToScene(overlay, scene, pendingChanges);
|
||||
_model.addToScene(scene, pendingChanges);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModelOverlay::removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> 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) {
|
||||
|
|
|
@ -32,6 +32,9 @@ public:
|
|||
|
||||
virtual ModelOverlay* createClone() const;
|
||||
|
||||
virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
|
||||
private:
|
||||
|
||||
Model _model;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <NumericalConstants.h>
|
||||
|
||||
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<render::Scene> 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<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_renderItemID);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <RegisteredMetaTypes.h>
|
||||
#include <SharedUtil.h> // for xColor
|
||||
#include <RenderArgs.h>
|
||||
#include <AABox.h>
|
||||
#include <render/Scene.h>
|
||||
|
||||
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<Overlay> Pointer;
|
||||
|
||||
typedef render::Payload<Overlay> Payload;
|
||||
typedef std::shared_ptr<render::Item::PayloadInterface> 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<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> 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
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <Application.h>
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <LODManager.h>
|
||||
#include <render/Scene.h>
|
||||
|
||||
#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<LODManager>();
|
||||
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<AvatarManager>()->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<LODManager>();
|
||||
RenderArgs args(NULL, Application::getInstance()->getDisplayViewFrustum(),
|
||||
lodManager->getOctreeSizeScale(),
|
||||
lodManager->getBoundaryLevelAdjust(),
|
||||
renderMode, renderSide, renderDebugFlags);
|
||||
|
||||
|
||||
foreach(Overlay* thisOverlay, _overlaysWorld) {
|
||||
Base3DOverlay* overlay3D = static_cast<Base3DOverlay*>(thisOverlay);
|
||||
if (overlay3D->getDrawInFront() != drawFront) {
|
||||
continue;
|
||||
}
|
||||
glPushMatrix();
|
||||
switch (thisOverlay->getAnchor()) {
|
||||
case Overlay::MY_AVATAR:
|
||||
if (!myAvatarComputed) {
|
||||
myAvatarRotation = avatar->getOrientation();
|
||||
myAvatarPosition = avatar->getPosition();
|
||||
angle = glm::degrees(glm::angle(myAvatarRotation));
|
||||
axis = glm::axis(myAvatarRotation);
|
||||
myAvatarScale = avatar->getScale();
|
||||
|
||||
myAvatarComputed = true;
|
||||
}
|
||||
|
||||
glTranslatef(myAvatarPosition.x, myAvatarPosition.y, myAvatarPosition.z);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
glScalef(myAvatarScale, myAvatarScale, myAvatarScale);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
thisOverlay->render(&args);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) {
|
||||
unsigned int thisID = 0;
|
||||
Overlay* thisOverlay = NULL;
|
||||
|
@ -201,6 +159,7 @@ unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& prope
|
|||
}
|
||||
|
||||
unsigned int Overlays::addOverlay(Overlay* overlay) {
|
||||
Overlay::Pointer overlayPointer(overlay);
|
||||
overlay->init(_scriptEngine);
|
||||
|
||||
QWriteLocker lock(&_lock);
|
||||
|
@ -209,19 +168,26 @@ unsigned int Overlays::addOverlay(Overlay* overlay) {
|
|||
if (overlay->is3D()) {
|
||||
Base3DOverlay* overlay3D = static_cast<Base3DOverlay*>(overlay);
|
||||
if (overlay3D->getDrawOnHUD()) {
|
||||
_overlaysHUD[thisID] = overlay;
|
||||
_overlaysHUD[thisID] = overlayPointer;
|
||||
} else {
|
||||
_overlaysWorld[thisID] = overlay;
|
||||
_overlaysWorld[thisID] = overlayPointer;
|
||||
|
||||
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
|
||||
overlayPointer->addToScene(overlayPointer, scene, pendingChanges);
|
||||
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
} else {
|
||||
_overlaysHUD[thisID] = overlay;
|
||||
_overlaysHUD[thisID] = overlayPointer;
|
||||
}
|
||||
|
||||
return thisID;
|
||||
}
|
||||
|
||||
unsigned int Overlays::cloneOverlay(unsigned int id) {
|
||||
Overlay* thisOverlay = NULL;
|
||||
Overlay::Pointer thisOverlay = NULL;
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
thisOverlay = _overlaysHUD[id];
|
||||
} else if (_overlaysWorld.contains(id)) {
|
||||
|
@ -237,7 +203,7 @@ unsigned int Overlays::cloneOverlay(unsigned int id) {
|
|||
|
||||
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
||||
QWriteLocker lock(&_lock);
|
||||
Overlay* thisOverlay = NULL;
|
||||
Overlay::Pointer thisOverlay;
|
||||
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
thisOverlay = _overlaysHUD[id];
|
||||
|
@ -247,7 +213,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
|||
|
||||
if (thisOverlay) {
|
||||
if (thisOverlay->is3D()) {
|
||||
Base3DOverlay* overlay3D = static_cast<Base3DOverlay*>(thisOverlay);
|
||||
Base3DOverlay* overlay3D = static_cast<Base3DOverlay*>(thisOverlay.get());
|
||||
|
||||
bool oldDrawOnHUD = overlay3D->getDrawOnHUD();
|
||||
thisOverlay->setProperties(properties);
|
||||
|
@ -272,7 +238,7 @@ bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
|||
}
|
||||
|
||||
void Overlays::deleteOverlay(unsigned int id) {
|
||||
Overlay* overlayToDelete;
|
||||
Overlay::Pointer overlayToDelete;
|
||||
|
||||
{
|
||||
QWriteLocker lock(&_lock);
|
||||
|
@ -296,7 +262,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
|||
}
|
||||
|
||||
QReadLocker lock(&_lock);
|
||||
QMapIterator<unsigned int, Overlay*> i(_overlaysHUD);
|
||||
QMapIterator<unsigned int, Overlay::Pointer> i(_overlaysHUD);
|
||||
i.toBack();
|
||||
|
||||
const float LARGE_NEGATIVE_FLOAT = -9999999;
|
||||
|
@ -309,14 +275,14 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
|||
i.previous();
|
||||
unsigned int thisID = i.key();
|
||||
if (i.value()->is3D()) {
|
||||
Base3DOverlay* thisOverlay = static_cast<Base3DOverlay*>(i.value());
|
||||
Base3DOverlay* thisOverlay = static_cast<Base3DOverlay*>(i.value().get());
|
||||
if (!thisOverlay->getIgnoreRayIntersection()) {
|
||||
if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace)) {
|
||||
return thisID;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Overlay2D* thisOverlay = static_cast<Overlay2D*>(i.value());
|
||||
Overlay2D* thisOverlay = static_cast<Overlay2D*>(i.value().get());
|
||||
if (thisOverlay->getVisible() && thisOverlay->isLoaded() &&
|
||||
thisOverlay->getBounds().contains(pointCopy.x, pointCopy.y, false)) {
|
||||
return thisID;
|
||||
|
@ -329,7 +295,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
|||
|
||||
OverlayPropertyResult Overlays::getProperty(unsigned int id, const QString& property) {
|
||||
OverlayPropertyResult result;
|
||||
Overlay* thisOverlay = NULL;
|
||||
Overlay::Pointer thisOverlay;
|
||||
QReadLocker lock(&_lock);
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
thisOverlay = _overlaysHUD[id];
|
||||
|
@ -376,12 +342,12 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray)
|
|||
float bestDistance = std::numeric_limits<float>::max();
|
||||
bool bestIsFront = false;
|
||||
RayToOverlayIntersectionResult result;
|
||||
QMapIterator<unsigned int, Overlay*> i(_overlaysWorld);
|
||||
QMapIterator<unsigned int, Overlay::Pointer> i(_overlaysWorld);
|
||||
i.toBack();
|
||||
while (i.hasPrevious()) {
|
||||
i.previous();
|
||||
unsigned int thisID = i.key();
|
||||
Base3DOverlay* thisOverlay = static_cast<Base3DOverlay*>(i.value());
|
||||
Base3DOverlay* thisOverlay = static_cast<Base3DOverlay*>(i.value().get());
|
||||
if (thisOverlay->getVisible() && !thisOverlay->getIgnoreRayIntersection() && thisOverlay->isLoaded()) {
|
||||
float thisDistance;
|
||||
BoxFace thisFace;
|
||||
|
@ -483,7 +449,7 @@ void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, R
|
|||
|
||||
bool Overlays::isLoaded(unsigned int id) {
|
||||
QReadLocker lock(&_lock);
|
||||
Overlay* thisOverlay = NULL;
|
||||
Overlay::Pointer thisOverlay = NULL;
|
||||
if (_overlaysHUD.contains(id)) {
|
||||
thisOverlay = _overlaysHUD[id];
|
||||
} else if (_overlaysWorld.contains(id)) {
|
||||
|
@ -495,16 +461,16 @@ bool Overlays::isLoaded(unsigned int id) {
|
|||
}
|
||||
|
||||
QSizeF Overlays::textSize(unsigned int id, const QString& text) const {
|
||||
Overlay* thisOverlay = _overlaysHUD[id];
|
||||
Overlay::Pointer thisOverlay = _overlaysHUD[id];
|
||||
if (thisOverlay) {
|
||||
if (typeid(*thisOverlay) == typeid(TextOverlay)) {
|
||||
return static_cast<TextOverlay*>(thisOverlay)->textSize(text);
|
||||
return static_cast<TextOverlay*>(thisOverlay.get())->textSize(text);
|
||||
}
|
||||
} else {
|
||||
thisOverlay = _overlaysWorld[id];
|
||||
if (thisOverlay) {
|
||||
if (typeid(*thisOverlay) == typeid(Text3DOverlay)) {
|
||||
return static_cast<Text3DOverlay*>(thisOverlay)->textSize(text);
|
||||
return static_cast<Text3DOverlay*>(thisOverlay.get())->textSize(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,10 +53,7 @@ public:
|
|||
~Overlays();
|
||||
void init();
|
||||
void update(float deltatime);
|
||||
void renderWorld(bool drawFront, RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE,
|
||||
RenderArgs::RenderSide renderSide = RenderArgs::MONO,
|
||||
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE);
|
||||
void renderHUD();
|
||||
void renderHUD(RenderArgs* renderArgs);
|
||||
|
||||
public slots:
|
||||
/// adds an overlay with the specific properties
|
||||
|
@ -92,9 +89,10 @@ public slots:
|
|||
QSizeF textSize(unsigned int id, const QString& text) const;
|
||||
|
||||
private:
|
||||
QMap<unsigned int, Overlay*> _overlaysHUD;
|
||||
QMap<unsigned int, Overlay*> _overlaysWorld;
|
||||
QList<Overlay*> _overlaysToDelete;
|
||||
void cleanupOverlaysToDelete();
|
||||
QMap<unsigned int, Overlay::Pointer> _overlaysHUD;
|
||||
QMap<unsigned int, Overlay::Pointer> _overlaysWorld;
|
||||
QList<Overlay::Pointer> _overlaysToDelete;
|
||||
unsigned int _nextOverlayID;
|
||||
QReadWriteLock _lock;
|
||||
QReadWriteLock _deleteLock;
|
||||
|
|
75
interface/src/ui/overlays/OverlaysPayload.cpp
Normal file
75
interface/src/ui/overlays/OverlaysPayload.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// OverlaysPayload.cpp
|
||||
// interface/src/ui/overlays
|
||||
//
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QScriptValueIterator>
|
||||
|
||||
#include <limits>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <Application.h>
|
||||
#include <avatar/AvatarManager.h>
|
||||
#include <LODManager.h>
|
||||
#include <render/Scene.h>
|
||||
|
||||
#include "BillboardOverlay.h"
|
||||
#include "Circle3DOverlay.h"
|
||||
#include "Cube3DOverlay.h"
|
||||
#include "ImageOverlay.h"
|
||||
#include "Line3DOverlay.h"
|
||||
#include "LocalModelsOverlay.h"
|
||||
#include "ModelOverlay.h"
|
||||
#include "Overlays.h"
|
||||
#include "Rectangle3DOverlay.h"
|
||||
#include "Sphere3DOverlay.h"
|
||||
#include "Grid3DOverlay.h"
|
||||
#include "TextOverlay.h"
|
||||
#include "Text3DOverlay.h"
|
||||
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) {
|
||||
if (overlay->is3D() && !static_cast<Base3DOverlay*>(overlay.get())->getDrawOnHUD()) {
|
||||
if (static_cast<Base3DOverlay*>(overlay.get())->getDrawInFront()) {
|
||||
return ItemKey::Builder().withTypeShape().withNoDepthSort().build();
|
||||
} else {
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
}
|
||||
} else {
|
||||
return ItemKey::Builder().withTypeShape().withViewSpace().build();
|
||||
}
|
||||
}
|
||||
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
|
||||
if (overlay->is3D()) {
|
||||
return static_cast<Base3DOverlay*>(overlay.get())->getBounds();
|
||||
} else {
|
||||
QRect bounds = static_cast<Overlay2D*>(overlay.get())->getBounds();
|
||||
return AABox(glm::vec3(bounds.x(), bounds.y(), 0.0f), glm::vec3(bounds.width(), bounds.height(), 0.1f));
|
||||
}
|
||||
}
|
||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||
if (args) {
|
||||
glPushMatrix();
|
||||
if (overlay->getAnchor() == Overlay::MY_AVATAR) {
|
||||
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
glm::quat myAvatarRotation = avatar->getOrientation();
|
||||
glm::vec3 myAvatarPosition = avatar->getPosition();
|
||||
float angle = glm::degrees(glm::angle(myAvatarRotation));
|
||||
glm::vec3 axis = glm::axis(myAvatarRotation);
|
||||
float myAvatarScale = avatar->getScale();
|
||||
|
||||
glTranslatef(myAvatarPosition.x, myAvatarPosition.y, myAvatarPosition.z);
|
||||
glRotatef(angle, axis.x, axis.y, axis.z);
|
||||
glScalef(myAvatarScale, myAvatarScale, myAvatarScale);
|
||||
}
|
||||
overlay->render(args);
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,15 +11,12 @@
|
|||
// include this before QGLWidget, which includes an earlier version of OpenGL
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <TextRenderer.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Text3DOverlay.h"
|
||||
|
||||
const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 };
|
||||
const float DEFAULT_BACKGROUND_ALPHA = 0.7f;
|
||||
const float DEFAULT_MARGIN = 0.1f;
|
||||
const int FIXED_FONT_POINT_SIZE = 40;
|
||||
const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 40.0f; // this is a ratio determined through experimentation
|
||||
const float LINE_SCALE_RATIO = 1.2f;
|
||||
|
||||
|
@ -50,6 +47,7 @@ Text3DOverlay::Text3DOverlay(const Text3DOverlay* text3DOverlay) :
|
|||
}
|
||||
|
||||
Text3DOverlay::~Text3DOverlay() {
|
||||
delete _textRenderer;
|
||||
}
|
||||
|
||||
xColor Text3DOverlay::getBackgroundColor() {
|
||||
|
@ -106,8 +104,7 @@ void Text3DOverlay::render(RenderArgs* args) {
|
|||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
|
||||
|
||||
// Same font properties as textSize()
|
||||
TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
|
||||
float maxHeight = (float)textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
|
||||
float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
|
||||
|
||||
float scaleFactor = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
|
||||
|
||||
|
@ -124,7 +121,7 @@ void Text3DOverlay::render(RenderArgs* args) {
|
|||
enableClipPlane(GL_CLIP_PLANE3, 0.0f, 1.0f, 0.0f, -clipMinimum.y);
|
||||
|
||||
glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, getAlpha() };
|
||||
textRenderer->draw(0, 0, _text, textColor);
|
||||
_textRenderer->draw(0, 0, _text, textColor);
|
||||
|
||||
glDisable(GL_CLIP_PLANE0);
|
||||
glDisable(GL_CLIP_PLANE1);
|
||||
|
@ -228,10 +225,9 @@ Text3DOverlay* Text3DOverlay::createClone() const {
|
|||
}
|
||||
|
||||
QSizeF Text3DOverlay::textSize(const QString& text) const {
|
||||
auto textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
|
||||
auto extents = textRenderer->computeExtent(text);
|
||||
auto extents = _textRenderer->computeExtent(text);
|
||||
|
||||
float maxHeight = (float)textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
|
||||
float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
|
||||
float pointToWorldScale = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight;
|
||||
|
||||
return QSizeF(extents.x, extents.y) * pointToWorldScale;
|
||||
|
|
|
@ -17,8 +17,12 @@
|
|||
#include <QString>
|
||||
|
||||
#include <RenderArgs.h>
|
||||
#include <TextRenderer.h>
|
||||
|
||||
#include "Planar3DOverlay.h"
|
||||
|
||||
const int FIXED_FONT_POINT_SIZE = 40;
|
||||
|
||||
class Text3DOverlay : public Planar3DOverlay {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -58,6 +62,8 @@ public:
|
|||
private:
|
||||
void enableClipPlane(GLenum plane, float x, float y, float z, float w);
|
||||
|
||||
TextRenderer* _textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
|
||||
|
||||
QString _text;
|
||||
xColor _backgroundColor;
|
||||
float _backgroundAlpha;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <TextRenderer.h>
|
||||
|
||||
#include "TextOverlay.h"
|
||||
|
||||
|
@ -25,6 +24,7 @@ TextOverlay::TextOverlay() :
|
|||
_topMargin(DEFAULT_MARGIN),
|
||||
_fontSize(DEFAULT_FONTSIZE)
|
||||
{
|
||||
_textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT);
|
||||
}
|
||||
|
||||
TextOverlay::TextOverlay(const TextOverlay* textOverlay) :
|
||||
|
@ -36,9 +36,11 @@ TextOverlay::TextOverlay(const TextOverlay* textOverlay) :
|
|||
_topMargin(textOverlay->_topMargin),
|
||||
_fontSize(textOverlay->_fontSize)
|
||||
{
|
||||
_textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT);
|
||||
}
|
||||
|
||||
TextOverlay::~TextOverlay() {
|
||||
delete _textRenderer;
|
||||
}
|
||||
|
||||
xColor TextOverlay::getBackgroundColor() {
|
||||
|
@ -79,9 +81,6 @@ void TextOverlay::render(RenderArgs* args) {
|
|||
glm::vec2 topLeft(left, top);
|
||||
glm::vec2 bottomRight(right, bottom);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, quadColor);
|
||||
|
||||
// Same font properties as textSize()
|
||||
TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT);
|
||||
|
||||
const int leftAdjust = -1; // required to make text render relative to left edge of bounds
|
||||
const int topAdjust = -2; // required to make text render relative to top edge of bounds
|
||||
|
@ -90,7 +89,7 @@ void TextOverlay::render(RenderArgs* args) {
|
|||
|
||||
float alpha = getAlpha();
|
||||
glm::vec4 textColor = {_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, alpha };
|
||||
textRenderer->draw(x, y, _text, textColor);
|
||||
_textRenderer->draw(x, y, _text, textColor);
|
||||
}
|
||||
|
||||
void TextOverlay::setProperties(const QScriptValue& properties) {
|
||||
|
@ -163,8 +162,7 @@ QScriptValue TextOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
QSizeF TextOverlay::textSize(const QString& text) const {
|
||||
auto textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT);
|
||||
auto extents = textRenderer->computeExtent(text);
|
||||
auto extents = _textRenderer->computeExtent(text);
|
||||
|
||||
return QSizeF(extents.x, extents.y);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <QString>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <TextRenderer.h>
|
||||
|
||||
#include "Overlay.h"
|
||||
#include "Overlay2D.h"
|
||||
|
@ -58,6 +59,9 @@ public:
|
|||
QSizeF textSize(const QString& text) const; // Pixels
|
||||
|
||||
private:
|
||||
|
||||
TextRenderer* _textRenderer = nullptr;
|
||||
|
||||
QString _text;
|
||||
xColor _backgroundColor;
|
||||
float _backgroundAlpha;
|
||||
|
|
|
@ -153,6 +153,7 @@ void AudioClient::reset() {
|
|||
}
|
||||
|
||||
void AudioClient::audioMixerKilled() {
|
||||
_hasReceivedFirstPacket = false;
|
||||
_outgoingAvatarAudioSequenceNumber = 0;
|
||||
_stats.reset();
|
||||
}
|
||||
|
@ -481,6 +482,7 @@ void AudioClient::start() {
|
|||
qCDebug(audioclient) << "Unable to set up audio input because of a problem with input format.";
|
||||
qCDebug(audioclient) << "The closest format available is" << inputDeviceInfo.nearestFormat(_desiredInputFormat);
|
||||
}
|
||||
|
||||
if (!outputFormatSupported) {
|
||||
qCDebug(audioclient) << "Unable to set up audio output because of a problem with output format.";
|
||||
qCDebug(audioclient) << "The closest format available is" << outputDeviceInfo.nearestFormat(_desiredOutputFormat);
|
||||
|
@ -489,6 +491,7 @@ void AudioClient::start() {
|
|||
if (_audioInput) {
|
||||
_inputFrameBuffer.initialize( _inputFormat.channelCount(), _audioInput->bufferSize() * 8 );
|
||||
}
|
||||
|
||||
_inputGain.initialize();
|
||||
_sourceGain.initialize();
|
||||
_noiseSource.initialize();
|
||||
|
@ -926,6 +929,14 @@ void AudioClient::addReceivedAudioToStream(const QByteArray& audioByteArray) {
|
|||
DependencyManager::get<NodeList>()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket);
|
||||
|
||||
if (_audioOutput) {
|
||||
|
||||
if (!_hasReceivedFirstPacket) {
|
||||
_hasReceivedFirstPacket = true;
|
||||
|
||||
// have the audio scripting interface emit a signal to say we just connected to mixer
|
||||
emit receivedFirstPacket();
|
||||
}
|
||||
|
||||
// Audio output must exist and be correctly set up if we're going to process received audio
|
||||
_receivedAudioStream.parseData(audioByteArray);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <MixedProcessedAudioStream.h>
|
||||
#include <RingBufferHistory.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <Sound.h>
|
||||
#include <StDev.h>
|
||||
|
||||
#include "AudioIOStats.h"
|
||||
|
@ -57,7 +58,7 @@ static const int NUM_AUDIO_CHANNELS = 2;
|
|||
static const int DEFAULT_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 3;
|
||||
static const int MIN_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 1;
|
||||
static const int MAX_AUDIO_OUTPUT_BUFFER_SIZE_FRAMES = 20;
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_WIN)
|
||||
#if defined(Q_OS_ANDROID) || defined(Q_OS_WIN)
|
||||
static const int DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_ENABLED = false;
|
||||
#else
|
||||
static const int DEFAULT_AUDIO_OUTPUT_STARVE_DETECTION_ENABLED = true;
|
||||
|
@ -88,14 +89,14 @@ public:
|
|||
void stop() { close(); }
|
||||
qint64 readData(char * data, qint64 maxSize);
|
||||
qint64 writeData(const char * data, qint64 maxSize) { return 0; }
|
||||
|
||||
|
||||
int getRecentUnfulfilledReads() { int unfulfilledReads = _unfulfilledReads; _unfulfilledReads = 0; return unfulfilledReads; }
|
||||
private:
|
||||
MixedProcessedAudioStream& _receivedAudioStream;
|
||||
AudioClient* _audio;
|
||||
int _unfulfilledReads;
|
||||
};
|
||||
|
||||
|
||||
const MixedProcessedAudioStream& getReceivedAudioStream() const { return _receivedAudioStream; }
|
||||
MixedProcessedAudioStream& getReceivedAudioStream() { return _receivedAudioStream; }
|
||||
|
||||
|
@ -105,30 +106,30 @@ public:
|
|||
float getAudioAverageInputLoudness() const { return _lastInputLoudness; }
|
||||
|
||||
int getDesiredJitterBufferFrames() const { return _receivedAudioStream.getDesiredJitterBufferFrames(); }
|
||||
|
||||
|
||||
bool isMuted() { return _muted; }
|
||||
|
||||
|
||||
const AudioIOStats& getStats() const { return _stats; }
|
||||
|
||||
float getInputRingBufferMsecsAvailable() const;
|
||||
float getAudioOutputMsecsUnplayed() const;
|
||||
|
||||
int getOutputBufferSize() { return _outputBufferSizeFrames.get(); }
|
||||
|
||||
|
||||
bool getOutputStarveDetectionEnabled() { return _outputStarveDetectionEnabled.get(); }
|
||||
void setOutputStarveDetectionEnabled(bool enabled) { _outputStarveDetectionEnabled.set(enabled); }
|
||||
|
||||
int getOutputStarveDetectionPeriod() { return _outputStarveDetectionPeriodMsec.get(); }
|
||||
void setOutputStarveDetectionPeriod(int msecs) { _outputStarveDetectionPeriodMsec.set(msecs); }
|
||||
|
||||
|
||||
int getOutputStarveDetectionThreshold() { return _outputStarveDetectionThreshold.get(); }
|
||||
void setOutputStarveDetectionThreshold(int threshold) { _outputStarveDetectionThreshold.set(threshold); }
|
||||
|
||||
|
||||
void setPositionGetter(AudioPositionGetter positionGetter) { _positionGetter = positionGetter; }
|
||||
void setOrientationGetter(AudioOrientationGetter orientationGetter) { _orientationGetter = orientationGetter; }
|
||||
|
||||
static const float CALLBACK_ACCELERATOR_RATIO;
|
||||
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
void stop();
|
||||
|
@ -140,7 +141,7 @@ public slots:
|
|||
void reset();
|
||||
void audioMixerKilled();
|
||||
void toggleMute();
|
||||
|
||||
|
||||
virtual void enableAudioSourceInject(bool enable);
|
||||
virtual void selectAudioSourcePinkNoise();
|
||||
virtual void selectAudioSourceSine440();
|
||||
|
@ -148,10 +149,10 @@ public slots:
|
|||
virtual void setIsStereoInput(bool stereo);
|
||||
|
||||
void toggleAudioNoiseReduction() { _isNoiseGateEnabled = !_isNoiseGateEnabled; }
|
||||
|
||||
|
||||
void toggleLocalEcho() { _shouldEchoLocally = !_shouldEchoLocally; }
|
||||
void toggleServerEcho() { _shouldEchoToServer = !_shouldEchoToServer; }
|
||||
|
||||
|
||||
void processReceivedSamples(const QByteArray& inputBuffer, QByteArray& outputBuffer);
|
||||
void sendMuteEnvironmentPacket();
|
||||
|
||||
|
@ -172,10 +173,10 @@ public slots:
|
|||
void setReverbOptions(const AudioEffectOptions* options);
|
||||
|
||||
void outputNotify();
|
||||
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
|
||||
signals:
|
||||
bool muteToggled();
|
||||
void inputReceived(const QByteArray& inputSamples);
|
||||
|
@ -184,14 +185,16 @@ signals:
|
|||
|
||||
void deviceChanged();
|
||||
|
||||
void receivedFirstPacket();
|
||||
|
||||
protected:
|
||||
AudioClient();
|
||||
~AudioClient();
|
||||
|
||||
|
||||
virtual void customDeleter() {
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void outputFormatChanged();
|
||||
|
||||
|
@ -216,35 +219,35 @@ private:
|
|||
|
||||
QString _inputAudioDeviceName;
|
||||
QString _outputAudioDeviceName;
|
||||
|
||||
|
||||
quint64 _outputStarveDetectionStartTimeMsec;
|
||||
int _outputStarveDetectionCount;
|
||||
|
||||
|
||||
Setting::Handle<int> _outputBufferSizeFrames;
|
||||
Setting::Handle<bool> _outputStarveDetectionEnabled;
|
||||
Setting::Handle<int> _outputStarveDetectionPeriodMsec;
|
||||
// Maximum number of starves per _outputStarveDetectionPeriod before increasing buffer size
|
||||
Setting::Handle<int> _outputStarveDetectionThreshold;
|
||||
|
||||
|
||||
StDev _stdev;
|
||||
QElapsedTimer _timeSinceLastReceived;
|
||||
float _averagedLatency;
|
||||
float _lastInputLoudness;
|
||||
float _timeSinceLastClip;
|
||||
int _totalInputAudioSamples;
|
||||
|
||||
|
||||
bool _muted;
|
||||
bool _shouldEchoLocally;
|
||||
bool _shouldEchoToServer;
|
||||
bool _isNoiseGateEnabled;
|
||||
bool _audioSourceInjectEnabled;
|
||||
|
||||
|
||||
bool _reverb;
|
||||
AudioEffectOptions _scriptReverbOptions;
|
||||
AudioEffectOptions _zoneReverbOptions;
|
||||
AudioEffectOptions* _reverbOptions;
|
||||
ty_gverb* _gverb;
|
||||
|
||||
|
||||
// possible soxr streams needed for resample
|
||||
soxr* _inputToNetworkResampler;
|
||||
soxr* _networkToOutputResampler;
|
||||
|
@ -268,17 +271,17 @@ private:
|
|||
|
||||
// Input framebuffer
|
||||
AudioBufferFloat32 _inputFrameBuffer;
|
||||
|
||||
|
||||
// Input gain
|
||||
AudioGain _inputGain;
|
||||
|
||||
|
||||
// Post tone/pink noise generator gain
|
||||
AudioGain _sourceGain;
|
||||
|
||||
// Pink noise source
|
||||
bool _noiseSourceEnabled;
|
||||
AudioSourcePinkNoise _noiseSource;
|
||||
|
||||
|
||||
// Tone source
|
||||
bool _toneSourceEnabled;
|
||||
AudioSourceTone _toneSource;
|
||||
|
@ -286,17 +289,19 @@ private:
|
|||
quint16 _outgoingAvatarAudioSequenceNumber;
|
||||
|
||||
AudioOutputIODevice _audioOutputIODevice;
|
||||
|
||||
|
||||
AudioIOStats _stats;
|
||||
|
||||
|
||||
AudioNoiseGate _inputGate;
|
||||
|
||||
|
||||
AudioPositionGetter _positionGetter;
|
||||
AudioOrientationGetter _orientationGetter;
|
||||
|
||||
|
||||
QVector<QString> _inputDevices;
|
||||
QVector<QString> _outputDevices;
|
||||
void checkDevices();
|
||||
|
||||
bool _hasReceivedFirstPacket = false;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
AudioInjector::AudioInjector(QObject* parent) :
|
||||
QObject(parent)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions) :
|
||||
|
@ -39,24 +39,25 @@ AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOpt
|
|||
_audioData(audioData),
|
||||
_options(injectorOptions)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void AudioInjector::setIsFinished(bool isFinished) {
|
||||
_isFinished = isFinished;
|
||||
|
||||
// In all paths, regardless of isFinished argument. restart() passes false to prepare for new play, and injectToMixer() needs _shouldStop reset.
|
||||
_shouldStop = false;
|
||||
|
||||
if (_isFinished) {
|
||||
emit finished();
|
||||
|
||||
|
||||
if (_localBuffer) {
|
||||
_localBuffer->stop();
|
||||
_localBuffer->deleteLater();
|
||||
_localBuffer = NULL;
|
||||
}
|
||||
|
||||
|
||||
_isStarted = false;
|
||||
_shouldStop = false;
|
||||
|
||||
|
||||
if (_shouldDeleteAfterFinish) {
|
||||
// we've been asked to delete after finishing, trigger a queued deleteLater here
|
||||
qCDebug(audio) << "AudioInjector triggering delete from setIsFinished";
|
||||
|
@ -67,18 +68,19 @@ void AudioInjector::setIsFinished(bool isFinished) {
|
|||
|
||||
void AudioInjector::injectAudio() {
|
||||
if (!_isStarted) {
|
||||
_isStarted = true;
|
||||
// check if we need to offset the sound by some number of seconds
|
||||
if (_options.secondOffset > 0.0f) {
|
||||
|
||||
|
||||
// convert the offset into a number of bytes
|
||||
int byteOffset = (int) floorf(AudioConstants::SAMPLE_RATE * _options.secondOffset * (_options.stereo ? 2.0f : 1.0f));
|
||||
byteOffset *= sizeof(int16_t);
|
||||
|
||||
|
||||
_currentSendPosition = byteOffset;
|
||||
} else {
|
||||
_currentSendPosition = 0;
|
||||
}
|
||||
|
||||
|
||||
if (_options.localOnly) {
|
||||
injectLocally();
|
||||
} else {
|
||||
|
@ -86,12 +88,20 @@ void AudioInjector::injectAudio() {
|
|||
}
|
||||
} else {
|
||||
qCDebug(audio) << "AudioInjector::injectAudio called but already started.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioInjector::restart() {
|
||||
qCDebug(audio) << "Restarting an AudioInjector by stopping and starting over.";
|
||||
stop();
|
||||
connect(this, &AudioInjector::finished, this, &AudioInjector::restartPortionAfterFinished);
|
||||
if (!_isStarted || _isFinished) {
|
||||
emit finished();
|
||||
} else {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
void AudioInjector::restartPortionAfterFinished() {
|
||||
disconnect(this, &AudioInjector::finished, this, &AudioInjector::restartPortionAfterFinished);
|
||||
setIsFinished(false);
|
||||
QMetaObject::invokeMethod(this, "injectAudio", Qt::QueuedConnection);
|
||||
}
|
||||
|
@ -100,37 +110,37 @@ void AudioInjector::injectLocally() {
|
|||
bool success = false;
|
||||
if (_localAudioInterface) {
|
||||
if (_audioData.size() > 0) {
|
||||
|
||||
|
||||
_localBuffer = new AudioInjectorLocalBuffer(_audioData, this);
|
||||
|
||||
|
||||
_localBuffer->open(QIODevice::ReadOnly);
|
||||
_localBuffer->setShouldLoop(_options.loop);
|
||||
_localBuffer->setVolume(_options.volume);
|
||||
|
||||
|
||||
// give our current send position to the local buffer
|
||||
_localBuffer->setCurrentOffset(_currentSendPosition);
|
||||
|
||||
|
||||
success = _localAudioInterface->outputLocalInjector(_options.stereo, this);
|
||||
|
||||
|
||||
// if we're not looping and the buffer tells us it is empty then emit finished
|
||||
connect(_localBuffer, &AudioInjectorLocalBuffer::bufferEmpty, this, &AudioInjector::stop);
|
||||
|
||||
|
||||
if (!success) {
|
||||
qCDebug(audio) << "AudioInjector::injectLocally could not output locally via _localAudioInterface";
|
||||
}
|
||||
} else {
|
||||
qCDebug(audio) << "AudioInjector::injectLocally called without any data in Sound QByteArray";
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
qCDebug(audio) << "AudioInjector::injectLocally cannot inject locally with no local audio interface present.";
|
||||
}
|
||||
|
||||
|
||||
if (!success) {
|
||||
// we never started so we are finished, call our stop method
|
||||
stop();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
const uchar MAX_INJECTOR_VOLUME = 0xFF;
|
||||
|
@ -140,65 +150,65 @@ void AudioInjector::injectToMixer() {
|
|||
_currentSendPosition >= _audioData.size()) {
|
||||
_currentSendPosition = 0;
|
||||
}
|
||||
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
|
||||
// make sure we actually have samples downloaded to inject
|
||||
if (_audioData.size()) {
|
||||
|
||||
|
||||
// setup the packet for injected audio
|
||||
QByteArray injectAudioPacket = nodeList->byteArrayWithPopulatedHeader(PacketTypeInjectAudio);
|
||||
QDataStream packetStream(&injectAudioPacket, QIODevice::Append);
|
||||
|
||||
|
||||
// pack some placeholder sequence number for now
|
||||
int numPreSequenceNumberBytes = injectAudioPacket.size();
|
||||
packetStream << (quint16)0;
|
||||
|
||||
|
||||
// pack stream identifier (a generated UUID)
|
||||
packetStream << QUuid::createUuid();
|
||||
|
||||
|
||||
// pack the stereo/mono type of the stream
|
||||
packetStream << _options.stereo;
|
||||
|
||||
|
||||
// pack the flag for loopback
|
||||
uchar loopbackFlag = (uchar) true;
|
||||
packetStream << loopbackFlag;
|
||||
|
||||
|
||||
// pack the position for injected audio
|
||||
int positionOptionOffset = injectAudioPacket.size();
|
||||
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.position),
|
||||
sizeof(_options.position));
|
||||
|
||||
|
||||
// pack our orientation for injected audio
|
||||
int orientationOptionOffset = injectAudioPacket.size();
|
||||
packetStream.writeRawData(reinterpret_cast<const char*>(&_options.orientation),
|
||||
sizeof(_options.orientation));
|
||||
|
||||
|
||||
// pack zero for radius
|
||||
float radius = 0;
|
||||
packetStream << radius;
|
||||
|
||||
|
||||
// pack 255 for attenuation byte
|
||||
int volumeOptionOffset = injectAudioPacket.size();
|
||||
quint8 volume = MAX_INJECTOR_VOLUME * _options.volume;
|
||||
packetStream << volume;
|
||||
|
||||
|
||||
packetStream << _options.ignorePenumbra;
|
||||
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
int nextFrame = 0;
|
||||
|
||||
|
||||
int numPreAudioDataBytes = injectAudioPacket.size();
|
||||
bool shouldLoop = _options.loop;
|
||||
|
||||
|
||||
// loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks
|
||||
quint16 outgoingInjectedAudioSequenceNumber = 0;
|
||||
while (_currentSendPosition < _audioData.size() && !_shouldStop) {
|
||||
|
||||
|
||||
int bytesToCopy = std::min(((_options.stereo) ? 2 : 1) * AudioConstants::NETWORK_FRAME_BYTES_PER_CHANNEL,
|
||||
_audioData.size() - _currentSendPosition);
|
||||
|
||||
|
||||
// Measure the loudness of this frame
|
||||
_loudness = 0.0f;
|
||||
for (int i = 0; i < bytesToCopy; i += sizeof(int16_t)) {
|
||||
|
@ -215,45 +225,45 @@ void AudioInjector::injectToMixer() {
|
|||
sizeof(_options.orientation));
|
||||
volume = MAX_INJECTOR_VOLUME * _options.volume;
|
||||
memcpy(injectAudioPacket.data() + volumeOptionOffset, &volume, sizeof(volume));
|
||||
|
||||
|
||||
// resize the QByteArray to the right size
|
||||
injectAudioPacket.resize(numPreAudioDataBytes + bytesToCopy);
|
||||
|
||||
// pack the sequence number
|
||||
memcpy(injectAudioPacket.data() + numPreSequenceNumberBytes,
|
||||
&outgoingInjectedAudioSequenceNumber, sizeof(quint16));
|
||||
|
||||
|
||||
// copy the next NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL bytes to the packet
|
||||
memcpy(injectAudioPacket.data() + numPreAudioDataBytes,
|
||||
_audioData.data() + _currentSendPosition, bytesToCopy);
|
||||
|
||||
|
||||
// grab our audio mixer from the NodeList, if it exists
|
||||
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||
|
||||
|
||||
// send off this audio packet
|
||||
nodeList->writeDatagram(injectAudioPacket, audioMixer);
|
||||
outgoingInjectedAudioSequenceNumber++;
|
||||
|
||||
|
||||
_currentSendPosition += bytesToCopy;
|
||||
|
||||
|
||||
// send two packets before the first sleep so the mixer can start playback right away
|
||||
|
||||
|
||||
if (_currentSendPosition != bytesToCopy && _currentSendPosition < _audioData.size()) {
|
||||
|
||||
|
||||
// process events in case we have been told to stop and be deleted
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
|
||||
if (_shouldStop) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// not the first packet and not done
|
||||
// sleep for the appropriate time
|
||||
int usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000;
|
||||
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldLoop && _currentSendPosition >= _audioData.size()) {
|
||||
|
@ -261,13 +271,13 @@ void AudioInjector::injectToMixer() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
setIsFinished(true);
|
||||
}
|
||||
|
||||
void AudioInjector::stop() {
|
||||
_shouldStop = true;
|
||||
|
||||
|
||||
if (_options.localOnly) {
|
||||
// we're only a local injector, so we can say we are finished right away too
|
||||
setIsFinished(true);
|
||||
|
|
|
@ -59,6 +59,7 @@ public slots:
|
|||
void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; }
|
||||
float getLoudness() const { return _loudness; }
|
||||
bool isPlaying() const { return !_isFinished; }
|
||||
void restartPortionAfterFinished();
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
|
|
@ -53,21 +53,25 @@ Sound::Sound(const QUrl& url, bool isStereo) :
|
|||
_isStereo(isStereo),
|
||||
_isReady(false)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Sound::downloadFinished(QNetworkReply* reply) {
|
||||
// replace our byte array with the downloaded data
|
||||
QByteArray rawAudioByteArray = reply->readAll();
|
||||
QString fileName = reply->url().fileName();
|
||||
|
||||
if (reply->hasRawHeader("Content-Type")) {
|
||||
const QString WAV_EXTENSION = ".wav";
|
||||
|
||||
if (reply->hasRawHeader("Content-Type") || fileName.endsWith(WAV_EXTENSION)) {
|
||||
|
||||
QByteArray headerContentType = reply->rawHeader("Content-Type");
|
||||
|
||||
// WAV audio file encountered
|
||||
if (headerContentType == "audio/x-wav"
|
||||
|| headerContentType == "audio/wav"
|
||||
|| headerContentType == "audio/wave") {
|
||||
|| headerContentType == "audio/wave"
|
||||
|| fileName.endsWith(WAV_EXTENSION)) {
|
||||
|
||||
QByteArray outputAudioByteArray;
|
||||
|
||||
|
@ -80,7 +84,7 @@ void Sound::downloadFinished(QNetworkReply* reply) {
|
|||
_isStereo = true;
|
||||
qCDebug(audio) << "Processing sound of" << rawAudioByteArray.size() << "bytes from" << reply->url() << "as stereo audio file.";
|
||||
}
|
||||
|
||||
|
||||
// Process as RAW file
|
||||
downSample(rawAudioByteArray);
|
||||
}
|
||||
|
@ -88,7 +92,7 @@ void Sound::downloadFinished(QNetworkReply* reply) {
|
|||
} else {
|
||||
qCDebug(audio) << "Network reply without 'Content-Type'.";
|
||||
}
|
||||
|
||||
|
||||
_isReady = true;
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
@ -99,16 +103,16 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) {
|
|||
|
||||
// we want to convert it to the format that the audio-mixer wants
|
||||
// which is signed, 16-bit, 24Khz
|
||||
|
||||
|
||||
int numSourceSamples = rawAudioByteArray.size() / sizeof(AudioConstants::AudioSample);
|
||||
|
||||
|
||||
int numDestinationBytes = rawAudioByteArray.size() / sizeof(AudioConstants::AudioSample);
|
||||
if (_isStereo && numSourceSamples % 2 != 0) {
|
||||
numDestinationBytes += sizeof(AudioConstants::AudioSample);
|
||||
}
|
||||
|
||||
|
||||
_byteArray.resize(numDestinationBytes);
|
||||
|
||||
|
||||
int16_t* sourceSamples = (int16_t*) rawAudioByteArray.data();
|
||||
int16_t* destinationSamples = (int16_t*) _byteArray.data();
|
||||
|
||||
|
@ -134,22 +138,22 @@ void Sound::downSample(const QByteArray& rawAudioByteArray) {
|
|||
}
|
||||
|
||||
void Sound::trimFrames() {
|
||||
|
||||
|
||||
const uint32_t inputFrameCount = _byteArray.size() / sizeof(int16_t);
|
||||
const uint32_t trimCount = 1024; // number of leading and trailing frames to trim
|
||||
|
||||
|
||||
if (inputFrameCount <= (2 * trimCount)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int16_t* inputFrameData = (int16_t*)_byteArray.data();
|
||||
|
||||
AudioEditBufferFloat32 editBuffer(1, inputFrameCount);
|
||||
editBuffer.copyFrames(1, inputFrameCount, inputFrameData, false /*copy in*/);
|
||||
|
||||
|
||||
editBuffer.linearFade(0, trimCount, true);
|
||||
editBuffer.linearFade(inputFrameCount - trimCount, inputFrameCount, false);
|
||||
|
||||
|
||||
editBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/);
|
||||
}
|
||||
|
||||
|
@ -238,7 +242,7 @@ void Sound::interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& ou
|
|||
} else if (qFromLittleEndian<quint16>(fileHeader.wave.numChannels) > 2) {
|
||||
qCDebug(audio) << "Currently not support audio files with more than 2 channels.";
|
||||
}
|
||||
|
||||
|
||||
if (qFromLittleEndian<quint16>(fileHeader.wave.bitsPerSample) != 16) {
|
||||
qCDebug(audio) << "Currently not supporting non 16bit audio files.";
|
||||
return;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_AvatarData_h
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
/* VS2010 defines stdint.h, but not inttypes.h */
|
||||
#if defined(_MSC_VER)
|
||||
typedef signed char int8_t;
|
||||
|
@ -57,6 +58,10 @@ typedef unsigned long long quint64;
|
|||
#include "Recorder.h"
|
||||
#include "Referential.h"
|
||||
|
||||
typedef std::shared_ptr<AvatarData> AvatarSharedPointer;
|
||||
typedef std::weak_ptr<AvatarData> AvatarWeakPointer;
|
||||
typedef QHash<QUuid, AvatarSharedPointer> AvatarHash;
|
||||
|
||||
// avatar motion behaviors
|
||||
const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0;
|
||||
const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1;
|
||||
|
|
|
@ -16,16 +16,14 @@
|
|||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <Node.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
typedef QSharedPointer<AvatarData> AvatarSharedPointer;
|
||||
typedef QWeakPointer<AvatarData> AvatarWeakPointer;
|
||||
typedef QHash<QUuid, AvatarSharedPointer> AvatarHash;
|
||||
|
||||
class AvatarHashMap : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
|
|
@ -23,4 +23,4 @@ find_package(Soxr REQUIRED)
|
|||
target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES})
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS})
|
||||
|
||||
link_hifi_libraries(shared gpu script-engine render-utils)
|
||||
link_hifi_libraries(shared gpu script-engine render render-utils)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/GLBackend.h>
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
|
@ -30,8 +31,11 @@
|
|||
#include <soxr.h>
|
||||
#include <AudioConstants.h>
|
||||
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
#include "RenderableBoxEntityItem.h"
|
||||
#include "RenderableLightEntityItem.h"
|
||||
#include "RenderableModelEntityItem.h"
|
||||
|
@ -95,6 +99,14 @@ void EntityTreeRenderer::clear() {
|
|||
}
|
||||
OctreeRenderer::clear();
|
||||
_entityScripts.clear();
|
||||
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
foreach(auto entity, _entitiesInScene) {
|
||||
entity->removeFromScene(entity, scene, pendingChanges);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
_entitiesInScene.clear();
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::init() {
|
||||
|
@ -395,127 +407,107 @@ void EntityTreeRenderer::leaveAllEntities() {
|
|||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
}
|
||||
}
|
||||
void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode,
|
||||
RenderArgs::RenderSide renderSide,
|
||||
RenderArgs::DebugFlags renderDebugFlags) {
|
||||
|
||||
void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone) {
|
||||
QSharedPointer<SceneScriptingInterface> scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
if (zone) {
|
||||
if (!_hasPreviousZone) {
|
||||
_previousKeyLightColor = scene->getKeyLightColor();
|
||||
_previousKeyLightIntensity = scene->getKeyLightIntensity();
|
||||
_previousKeyLightAmbientIntensity = scene->getKeyLightAmbientIntensity();
|
||||
_previousKeyLightDirection = scene->getKeyLightDirection();
|
||||
_previousStageSunModelEnabled = scene->isStageSunModelEnabled();
|
||||
_previousStageLongitude = scene->getStageLocationLongitude();
|
||||
_previousStageLatitude = scene->getStageLocationLatitude();
|
||||
_previousStageAltitude = scene->getStageLocationAltitude();
|
||||
_previousStageHour = scene->getStageDayTime();
|
||||
_previousStageDay = scene->getStageYearTime();
|
||||
_hasPreviousZone = true;
|
||||
}
|
||||
scene->setKeyLightColor(zone->getKeyLightColorVec3());
|
||||
scene->setKeyLightIntensity(zone->getKeyLightIntensity());
|
||||
scene->setKeyLightAmbientIntensity(zone->getKeyLightAmbientIntensity());
|
||||
scene->setKeyLightDirection(zone->getKeyLightDirection());
|
||||
scene->setStageSunModelEnable(zone->getStageProperties().getSunModelEnabled());
|
||||
scene->setStageLocation(zone->getStageProperties().getLongitude(), zone->getStageProperties().getLatitude(),
|
||||
zone->getStageProperties().getAltitude());
|
||||
scene->setStageDayTime(zone->getStageProperties().calculateHour());
|
||||
scene->setStageYearTime(zone->getStageProperties().calculateDay());
|
||||
|
||||
if (zone->getBackgroundMode() == BACKGROUND_MODE_ATMOSPHERE) {
|
||||
EnvironmentData data = zone->getEnvironmentData();
|
||||
glm::vec3 keyLightDirection = scene->getKeyLightDirection();
|
||||
glm::vec3 inverseKeyLightDirection = keyLightDirection * -1.0f;
|
||||
|
||||
// NOTE: is this right? It seems like the "sun" should be based on the center of the
|
||||
// atmosphere, not where the camera is.
|
||||
glm::vec3 keyLightLocation = _viewState->getAvatarPosition()
|
||||
+ (inverseKeyLightDirection * data.getAtmosphereOuterRadius());
|
||||
|
||||
data.setSunLocation(keyLightLocation);
|
||||
|
||||
const float KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO = 20.0f;
|
||||
float sunBrightness = scene->getKeyLightIntensity() * KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO;
|
||||
data.setSunBrightness(sunBrightness);
|
||||
|
||||
_viewState->overrideEnvironmentData(data);
|
||||
scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME);
|
||||
|
||||
} else {
|
||||
_viewState->endOverrideEnvironmentData();
|
||||
auto stage = scene->getSkyStage();
|
||||
if (zone->getBackgroundMode() == BACKGROUND_MODE_SKYBOX) {
|
||||
stage->getSkybox()->setColor(zone->getSkyboxProperties().getColorVec3());
|
||||
if (zone->getSkyboxProperties().getURL().isEmpty()) {
|
||||
stage->getSkybox()->setCubemap(gpu::TexturePointer());
|
||||
} else {
|
||||
// Update the Texture of the Skybox with the one pointed by this zone
|
||||
auto cubeMap = DependencyManager::get<TextureCache>()->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE);
|
||||
stage->getSkybox()->setCubemap(cubeMap->getGPUTexture());
|
||||
}
|
||||
stage->setBackgroundMode(model::SunSkyStage::SKY_BOX);
|
||||
} else {
|
||||
stage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_hasPreviousZone) {
|
||||
scene->setKeyLightColor(_previousKeyLightColor);
|
||||
scene->setKeyLightIntensity(_previousKeyLightIntensity);
|
||||
scene->setKeyLightAmbientIntensity(_previousKeyLightAmbientIntensity);
|
||||
scene->setKeyLightDirection(_previousKeyLightDirection);
|
||||
scene->setStageSunModelEnable(_previousStageSunModelEnabled);
|
||||
scene->setStageLocation(_previousStageLongitude, _previousStageLatitude,
|
||||
_previousStageAltitude);
|
||||
scene->setStageDayTime(_previousStageHour);
|
||||
scene->setStageYearTime(_previousStageDay);
|
||||
_hasPreviousZone = false;
|
||||
}
|
||||
_viewState->endOverrideEnvironmentData();
|
||||
scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::render(RenderArgs* renderArgs) {
|
||||
|
||||
if (_tree && !_shuttingDown) {
|
||||
Model::startScene(renderSide);
|
||||
|
||||
ViewFrustum* frustum = (renderMode == RenderArgs::SHADOW_RENDER_MODE) ?
|
||||
_viewState->getShadowViewFrustum() : _viewState->getCurrentViewFrustum();
|
||||
|
||||
RenderArgs args(this, frustum, getSizeScale(), getBoundaryLevelAdjust(),
|
||||
renderMode, renderSide, renderDebugFlags);
|
||||
renderArgs->_renderer = this;
|
||||
|
||||
_tree->lockForRead();
|
||||
|
||||
// Whenever you're in an intersection between zones, we will always choose the smallest zone.
|
||||
_bestZone = NULL;
|
||||
_bestZone = NULL; // NOTE: Is this what we want?
|
||||
_bestZoneVolume = std::numeric_limits<float>::max();
|
||||
_tree->recurseTreeWithOperation(renderOperation, &args);
|
||||
|
||||
QSharedPointer<SceneScriptingInterface> scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
|
||||
if (_bestZone) {
|
||||
if (!_hasPreviousZone) {
|
||||
_previousKeyLightColor = scene->getKeyLightColor();
|
||||
_previousKeyLightIntensity = scene->getKeyLightIntensity();
|
||||
_previousKeyLightAmbientIntensity = scene->getKeyLightAmbientIntensity();
|
||||
_previousKeyLightDirection = scene->getKeyLightDirection();
|
||||
_previousStageSunModelEnabled = scene->isStageSunModelEnabled();
|
||||
_previousStageLongitude = scene->getStageLocationLongitude();
|
||||
_previousStageLatitude = scene->getStageLocationLatitude();
|
||||
_previousStageAltitude = scene->getStageLocationAltitude();
|
||||
_previousStageHour = scene->getStageDayTime();
|
||||
_previousStageDay = scene->getStageYearTime();
|
||||
_hasPreviousZone = true;
|
||||
}
|
||||
scene->setKeyLightColor(_bestZone->getKeyLightColorVec3());
|
||||
scene->setKeyLightIntensity(_bestZone->getKeyLightIntensity());
|
||||
scene->setKeyLightAmbientIntensity(_bestZone->getKeyLightAmbientIntensity());
|
||||
scene->setKeyLightDirection(_bestZone->getKeyLightDirection());
|
||||
scene->setStageSunModelEnable(_bestZone->getStageProperties().getSunModelEnabled());
|
||||
scene->setStageLocation(_bestZone->getStageProperties().getLongitude(), _bestZone->getStageProperties().getLatitude(),
|
||||
_bestZone->getStageProperties().getAltitude());
|
||||
scene->setStageDayTime(_bestZone->getStageProperties().calculateHour());
|
||||
scene->setStageYearTime(_bestZone->getStageProperties().calculateDay());
|
||||
// FIX ME: right now the renderOperation does the following:
|
||||
// 1) determining the best zone (not really rendering)
|
||||
// 2) render the debug cell details
|
||||
// we should clean this up
|
||||
_tree->recurseTreeWithOperation(renderOperation, renderArgs);
|
||||
|
||||
if (_bestZone->getBackgroundMode() == BACKGROUND_MODE_ATMOSPHERE) {
|
||||
EnvironmentData data = _bestZone->getEnvironmentData();
|
||||
glm::vec3 keyLightDirection = scene->getKeyLightDirection();
|
||||
glm::vec3 inverseKeyLightDirection = keyLightDirection * -1.0f;
|
||||
|
||||
// NOTE: is this right? It seems like the "sun" should be based on the center of the
|
||||
// atmosphere, not where the camera is.
|
||||
glm::vec3 keyLightLocation = _viewState->getAvatarPosition()
|
||||
+ (inverseKeyLightDirection * data.getAtmosphereOuterRadius());
|
||||
|
||||
data.setSunLocation(keyLightLocation);
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
|
||||
const float KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO = 20.0f;
|
||||
float sunBrightness = scene->getKeyLightIntensity() * KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO;
|
||||
data.setSunBrightness(sunBrightness);
|
||||
|
||||
_viewState->overrideEnvironmentData(data);
|
||||
scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME);
|
||||
|
||||
} else {
|
||||
_viewState->endOverrideEnvironmentData();
|
||||
auto stage = scene->getSkyStage();
|
||||
if (_bestZone->getBackgroundMode() == BACKGROUND_MODE_SKYBOX) {
|
||||
stage->getSkybox()->setColor(_bestZone->getSkyboxProperties().getColorVec3());
|
||||
if (_bestZone->getSkyboxProperties().getURL().isEmpty()) {
|
||||
stage->getSkybox()->setCubemap(gpu::TexturePointer());
|
||||
} else {
|
||||
// Update the Texture of the Skybox with the one pointed by this zone
|
||||
auto cubeMap = DependencyManager::get<TextureCache>()->getTexture(_bestZone->getSkyboxProperties().getURL(), CUBE_TEXTURE);
|
||||
stage->getSkybox()->setCubemap(cubeMap->getGPUTexture());
|
||||
}
|
||||
stage->setBackgroundMode(model::SunSkyStage::SKY_BOX);
|
||||
} else {
|
||||
stage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (_hasPreviousZone) {
|
||||
scene->setKeyLightColor(_previousKeyLightColor);
|
||||
scene->setKeyLightIntensity(_previousKeyLightIntensity);
|
||||
scene->setKeyLightAmbientIntensity(_previousKeyLightAmbientIntensity);
|
||||
scene->setKeyLightDirection(_previousKeyLightDirection);
|
||||
scene->setStageSunModelEnable(_previousStageSunModelEnabled);
|
||||
scene->setStageLocation(_previousStageLongitude, _previousStageLatitude,
|
||||
_previousStageAltitude);
|
||||
scene->setStageDayTime(_previousStageHour);
|
||||
scene->setStageYearTime(_previousStageDay);
|
||||
_hasPreviousZone = false;
|
||||
}
|
||||
_viewState->endOverrideEnvironmentData();
|
||||
scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through
|
||||
}
|
||||
|
||||
// we must call endScene while we still have the tree locked so that no one deletes a model
|
||||
// on us while rendering the scene
|
||||
Model::endScene(renderMode, &args);
|
||||
_tree->unlock();
|
||||
|
||||
// stats...
|
||||
_meshesConsidered = args._meshesConsidered;
|
||||
_meshesRendered = args._meshesRendered;
|
||||
_meshesOutOfView = args._meshesOutOfView;
|
||||
_meshesTooSmall = args._meshesTooSmall;
|
||||
|
||||
_elementsTouched = args._elementsTouched;
|
||||
_itemsRendered = args._itemsRendered;
|
||||
_itemsOutOfView = args._itemsOutOfView;
|
||||
_itemsTooSmall = args._itemsTooSmall;
|
||||
|
||||
_materialSwitches = args._materialSwitches;
|
||||
_trianglesRendered = args._trianglesRendered;
|
||||
_quadsRendered = args._quadsRendered;
|
||||
|
||||
_translucentMeshPartsRendered = args._translucentMeshPartsRendered;
|
||||
_opaqueMeshPartsRendered = args._opaqueMeshPartsRendered;
|
||||
}
|
||||
deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup
|
||||
}
|
||||
|
@ -564,57 +556,36 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemP
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::renderElementProxy(EntityTreeElement* entityTreeElement) {
|
||||
void EntityTreeRenderer::renderElementProxy(EntityTreeElement* entityTreeElement, RenderArgs* args) {
|
||||
auto deferredLighting = DependencyManager::get<DeferredLightingEffect>();
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
Transform transform;
|
||||
|
||||
glm::vec3 elementCenter = entityTreeElement->getAACube().calcCenter();
|
||||
float elementSize = entityTreeElement->getScale();
|
||||
glPushMatrix();
|
||||
glTranslatef(elementCenter.x, elementCenter.y, elementCenter.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(elementSize, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
|
||||
auto drawWireCube = [&](glm::vec3 offset, float size, glm::vec4 color) {
|
||||
transform.setTranslation(elementCenter + offset);
|
||||
batch.setModelTransform(transform);
|
||||
deferredLighting->renderWireCube(batch, size, color);
|
||||
};
|
||||
|
||||
drawWireCube(glm::vec3(), elementSize, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
if (_displayElementChildProxies) {
|
||||
// draw the children
|
||||
float halfSize = elementSize / 2.0f;
|
||||
float quarterSize = elementSize / 4.0f;
|
||||
glPushMatrix();
|
||||
glTranslatef(elementCenter.x - quarterSize, elementCenter.y - quarterSize, elementCenter.z - quarterSize);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(halfSize, glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(elementCenter.x + quarterSize, elementCenter.y - quarterSize, elementCenter.z - quarterSize);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(halfSize, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(elementCenter.x - quarterSize, elementCenter.y + quarterSize, elementCenter.z - quarterSize);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(halfSize, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(elementCenter.x - quarterSize, elementCenter.y - quarterSize, elementCenter.z + quarterSize);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(halfSize, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(elementCenter.x + quarterSize, elementCenter.y + quarterSize, elementCenter.z + quarterSize);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(halfSize, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(elementCenter.x - quarterSize, elementCenter.y + quarterSize, elementCenter.z + quarterSize);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(halfSize, glm::vec4(0.0f, 0.5f, 0.5f, 1.0f));
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(elementCenter.x + quarterSize, elementCenter.y - quarterSize, elementCenter.z + quarterSize);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(halfSize, glm::vec4(0.5f, 0.0f, 0.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(elementCenter.x + quarterSize, elementCenter.y + quarterSize, elementCenter.z - quarterSize);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(halfSize, glm::vec4(0.0f, 0.5f, 0.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
|
||||
drawWireCube(glm::vec3(-quarterSize, -quarterSize, -quarterSize), halfSize, glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
|
||||
drawWireCube(glm::vec3(quarterSize, -quarterSize, -quarterSize), halfSize, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f));
|
||||
drawWireCube(glm::vec3(-quarterSize, quarterSize, -quarterSize), halfSize, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
||||
drawWireCube(glm::vec3(-quarterSize, -quarterSize, quarterSize), halfSize, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
|
||||
drawWireCube(glm::vec3(quarterSize, quarterSize, quarterSize), halfSize, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
drawWireCube(glm::vec3(-quarterSize, quarterSize, quarterSize), halfSize, glm::vec4(0.0f, 0.5f, 0.5f, 1.0f));
|
||||
drawWireCube(glm::vec3(quarterSize, -quarterSize, quarterSize), halfSize, glm::vec4(0.5f, 0.0f, 0.0f, 1.0f));
|
||||
drawWireCube(glm::vec3(quarterSize, quarterSize, -quarterSize), halfSize, glm::vec4(0.0f, 0.5f, 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -631,48 +602,35 @@ void EntityTreeRenderer::renderProxies(EntityItemPointer entity, RenderArgs* arg
|
|||
glm::vec3 minCenter = minCube.calcCenter();
|
||||
glm::vec3 entityBoxCenter = entityBox.calcCenter();
|
||||
glm::vec3 entityBoxScale = entityBox.getScale();
|
||||
|
||||
auto deferredLighting = DependencyManager::get<DeferredLightingEffect>();
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
Transform transform;
|
||||
|
||||
// draw the max bounding cube
|
||||
glPushMatrix();
|
||||
glTranslatef(maxCenter.x, maxCenter.y, maxCenter.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(maxCube.getScale(), glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
transform.setTranslation(maxCenter);
|
||||
batch.setModelTransform(transform);
|
||||
deferredLighting->renderWireCube(batch, maxCube.getScale(), glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
|
||||
|
||||
// draw the min bounding cube
|
||||
glPushMatrix();
|
||||
glTranslatef(minCenter.x, minCenter.y, minCenter.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(minCube.getScale(), glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
transform.setTranslation(minCenter);
|
||||
batch.setModelTransform(transform);
|
||||
deferredLighting->renderWireCube(batch, minCube.getScale(), glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
||||
|
||||
// draw the entityBox bounding box
|
||||
glPushMatrix();
|
||||
glTranslatef(entityBoxCenter.x, entityBoxCenter.y, entityBoxCenter.z);
|
||||
glScalef(entityBoxScale.x, entityBoxScale.y, entityBoxScale.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(1.0f, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
transform.setTranslation(entityBoxCenter);
|
||||
transform.setScale(entityBoxScale);
|
||||
batch.setModelTransform(transform);
|
||||
deferredLighting->renderWireCube(batch, 1.0f, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
|
||||
|
||||
|
||||
glm::vec3 position = entity->getPosition();
|
||||
glm::vec3 center = entity->getCenter();
|
||||
glm::vec3 dimensions = entity->getDimensions();
|
||||
glm::quat rotation = entity->getRotation();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(1.0f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f));
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
// Rotated bounding box
|
||||
batch.setModelTransform(entity->getTransformToCenter());
|
||||
deferredLighting->renderWireCube(batch, 1.0f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
|
||||
args->_elementsTouched++;
|
||||
// actually render it here...
|
||||
// we need to iterate the actual entityItems of the element
|
||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||
|
@ -685,7 +643,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
bool isShadowMode = args->_renderMode == RenderArgs::SHADOW_RENDER_MODE;
|
||||
|
||||
if (!isShadowMode && _displayModelElementProxy && numberOfEntities > 0) {
|
||||
renderElementProxy(entityTreeElement);
|
||||
renderElementProxy(entityTreeElement, args);
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < numberOfEntities; i++) {
|
||||
|
@ -715,36 +673,6 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render entityItem
|
||||
AABox entityBox = entityItem->getAABox();
|
||||
|
||||
// TODO: some entity types (like lights) might want to be rendered even
|
||||
// when they are outside of the view frustum...
|
||||
float distance = args->_viewFrustum->distanceToCamera(entityBox.calcCenter());
|
||||
|
||||
bool outOfView = args->_viewFrustum->boxInFrustum(entityBox) == ViewFrustum::OUTSIDE;
|
||||
if (!outOfView) {
|
||||
bool bigEnoughToRender = _viewState->shouldRenderMesh(entityBox.getLargestDimension(), distance);
|
||||
|
||||
if (bigEnoughToRender) {
|
||||
renderProxies(entityItem, args);
|
||||
|
||||
Glower* glower = NULL;
|
||||
if (entityItem->getGlowLevel() > 0.0f) {
|
||||
glower = new Glower(entityItem->getGlowLevel());
|
||||
}
|
||||
entityItem->render(args);
|
||||
args->_itemsRendered++;
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
} else {
|
||||
args->_itemsTooSmall++;
|
||||
}
|
||||
} else {
|
||||
args->_itemsOutOfView++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1070,12 +998,34 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
|||
checkAndCallUnload(entityID);
|
||||
}
|
||||
_entityScripts.remove(entityID);
|
||||
|
||||
// here's where we remove the entity payload from the scene
|
||||
if (_entitiesInScene.contains(entityID)) {
|
||||
auto entity = _entitiesInScene.take(entityID);
|
||||
render::PendingChanges pendingChanges;
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
entity->removeFromScene(entity, scene, pendingChanges);
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
||||
checkAndCallPreload(entityID);
|
||||
auto entity = static_cast<EntityTree*>(_tree)->findEntityByID(entityID);
|
||||
addEntityToScene(entity);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
|
||||
// here's where we add the entity payload to the scene
|
||||
render::PendingChanges pendingChanges;
|
||||
auto scene = _viewState->getMain3DScene();
|
||||
if (entity->addToScene(entity, scene, pendingChanges)) {
|
||||
_entitiesInScene.insert(entity->getEntityItemID(), entity);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
|
||||
|
||||
void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID) {
|
||||
if (_tree && !_shuttingDown) {
|
||||
checkAndCallUnload(entityID);
|
||||
|
@ -1244,4 +1194,3 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
|
|||
entityScriptB.property("collisionWithEntity").call(entityScriptA, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,9 +58,7 @@ public:
|
|||
void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode);
|
||||
|
||||
virtual void init();
|
||||
virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE,
|
||||
RenderArgs::RenderSide renderSide = RenderArgs::MONO,
|
||||
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE);
|
||||
virtual void render(RenderArgs* renderArgs) override;
|
||||
|
||||
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem);
|
||||
virtual const Model* getModelForEntityItem(EntityItemPointer entityItem);
|
||||
|
@ -125,7 +123,10 @@ protected:
|
|||
virtual Octree* createTree() { return new EntityTree(true); }
|
||||
|
||||
private:
|
||||
void renderElementProxy(EntityTreeElement* entityTreeElement);
|
||||
void addEntityToScene(EntityItemPointer entity);
|
||||
|
||||
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
|
||||
void renderElementProxy(EntityTreeElement* entityTreeElement, RenderArgs* args);
|
||||
void checkAndCallPreload(const EntityItemID& entityID);
|
||||
void checkAndCallUnload(const EntityItemID& entityID);
|
||||
|
||||
|
@ -187,6 +188,8 @@ private:
|
|||
float _previousStageHour;
|
||||
int _previousStageDay;
|
||||
|
||||
QHash<EntityItemID, EntityItemPointer> _entitiesInScene;
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_EntityTreeRenderer_h
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <PerfStat.h>
|
||||
|
@ -24,17 +25,8 @@ EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID,
|
|||
|
||||
void RenderableBoxEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableBoxEntityItem::render");
|
||||
assert(getType() == EntityTypes::Box);
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 center = getCenter();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
const float MAX_COLOR = 255.0f;
|
||||
|
||||
glm::vec4 cubeColor(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR,
|
||||
getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha());
|
||||
|
||||
Q_ASSERT(getType() == EntityTypes::Box);
|
||||
glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
|
||||
bool debugSimulationOwnership = args->_debugFlags & RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP;
|
||||
bool highlightSimulationOwnership = false;
|
||||
|
@ -43,22 +35,15 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
|||
const QUuid& myNodeID = nodeList->getSessionUUID();
|
||||
highlightSimulationOwnership = (getSimulatorID() == myNodeID);
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
if (highlightSimulationOwnership) {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(1.0f, cubeColor);
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(1.0f, cubeColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter());
|
||||
if (highlightSimulationOwnership) {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f, cubeColor);
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(batch, 1.0f, cubeColor);
|
||||
}
|
||||
|
||||
RenderableDebugableEntityItem::render(this, args);
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <BoxEntityItem.h>
|
||||
#include "RenderableDebugableEntityItem.h"
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class RenderableBoxEntityItem : public BoxEntityItem {
|
||||
public:
|
||||
|
@ -24,6 +25,8 @@ public:
|
|||
{ }
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
SIMPLE_RENDERABLE()
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,10 @@
|
|||
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <PhysicsEngine.h>
|
||||
|
||||
|
@ -21,48 +24,24 @@
|
|||
|
||||
void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, RenderArgs* args,
|
||||
float puffedOut, glm::vec4& color) {
|
||||
glm::vec3 position = entity->getPosition();
|
||||
glm::vec3 center = entity->getCenter();
|
||||
glm::vec3 dimensions = entity->getDimensions();
|
||||
glm::quat rotation = entity->getRotation();
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(1.0f + puffedOut, color);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(entity->getTransformToCenter());
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f + puffedOut, color);
|
||||
}
|
||||
|
||||
void RenderableDebugableEntityItem::renderHoverDot(EntityItem* entity, RenderArgs* args) {
|
||||
glm::vec3 position = entity->getPosition();
|
||||
glm::vec3 center = entity->getCenter();
|
||||
glm::vec3 dimensions = entity->getDimensions();
|
||||
glm::quat rotation = entity->getRotation();
|
||||
glm::vec4 blueColor(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
const int SLICES = 8, STACKS = 8;
|
||||
float radius = 0.05f;
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y + dimensions.y + radius, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
|
||||
glScalef(radius, radius, radius);
|
||||
|
||||
const int SLICES = 8;
|
||||
const int STACKS = 8;
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(0.5f, SLICES, STACKS, blueColor);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
glm::vec4 blueColor(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
Transform transform = entity->getTransformToCenter();
|
||||
// Cancel true dimensions and set scale to 2 * radius (diameter)
|
||||
transform.postScale(2.0f * glm::vec3(radius, radius, radius) / entity->getDimensions());
|
||||
batch.setModelTransform(transform);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, blueColor);
|
||||
}
|
||||
|
||||
void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) {
|
||||
|
|
41
libraries/entities-renderer/src/RenderableEntityItem.cpp
Normal file
41
libraries/entities-renderer/src/RenderableEntityItem.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// RenderableEntityItem.cpp
|
||||
// interface/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/6/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload) {
|
||||
if (payload && payload->entity) {
|
||||
if (payload->entity->getType() == EntityTypes::Light) {
|
||||
return ItemKey::Builder::light();
|
||||
}
|
||||
}
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload) {
|
||||
if (payload && payload->entity) {
|
||||
return payload->entity->getAABox();
|
||||
}
|
||||
return render::Item::Bound();
|
||||
}
|
||||
template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args) {
|
||||
if (args) {
|
||||
if (payload && payload->entity && payload->entity->getVisible()) {
|
||||
payload->entity->render(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
66
libraries/entities-renderer/src/RenderableEntityItem.h
Normal file
66
libraries/entities-renderer/src/RenderableEntityItem.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// RenderableEntityItem.h
|
||||
// interface/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/6/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_RenderableEntityItem_h
|
||||
#define hifi_RenderableEntityItem_h
|
||||
|
||||
#include <render/Scene.h>
|
||||
#include <EntityItem.h>
|
||||
|
||||
|
||||
class RenderableEntityItemProxy {
|
||||
public:
|
||||
RenderableEntityItemProxy(EntityItemPointer entity) : entity(entity) { }
|
||||
typedef render::Payload<RenderableEntityItemProxy> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
EntityItemPointer entity;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const RenderableEntityItemProxy::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const RenderableEntityItemProxy::Pointer& payload);
|
||||
template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
// Mixin class for implementing basic single item rendering
|
||||
class SimpleRenderableEntityItem {
|
||||
public:
|
||||
bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
_myItem = scene->allocateID();
|
||||
|
||||
auto renderData = RenderableEntityItemProxy::Pointer(new RenderableEntityItemProxy(self));
|
||||
auto renderPayload = render::PayloadPointer(new RenderableEntityItemProxy::Payload(renderData));
|
||||
|
||||
pendingChanges.resetItem(_myItem, renderPayload);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_myItem);
|
||||
}
|
||||
|
||||
private:
|
||||
render::ItemID _myItem;
|
||||
};
|
||||
|
||||
|
||||
#define SIMPLE_RENDERABLE() \
|
||||
public: \
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) { return _renderHelper.addToScene(self, scene, pendingChanges); } \
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) { _renderHelper.removeFromScene(self, scene, pendingChanges); } \
|
||||
private: \
|
||||
SimpleRenderableEntityItem _renderHelper;
|
||||
|
||||
|
||||
|
||||
#endif // hifi_RenderableEntityItem_h
|
|
@ -12,6 +12,7 @@
|
|||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <GLMHelpers.h>
|
||||
|
@ -31,12 +32,7 @@ void RenderableLightEntityItem::render(RenderArgs* args) {
|
|||
glm::quat rotation = getRotation();
|
||||
float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z);
|
||||
|
||||
const float MAX_COLOR = 255.0f;
|
||||
float colorR = getColor()[RED_INDEX] / MAX_COLOR;
|
||||
float colorG = getColor()[GREEN_INDEX] / MAX_COLOR;
|
||||
float colorB = getColor()[BLUE_INDEX] / MAX_COLOR;
|
||||
|
||||
glm::vec3 color = glm::vec3(colorR, colorG, colorB);
|
||||
glm::vec3 color = toGlm(getXColor());
|
||||
|
||||
float intensity = getIntensity();
|
||||
float exponent = getExponent();
|
||||
|
@ -49,21 +45,12 @@ void RenderableLightEntityItem::render(RenderArgs* args) {
|
|||
DependencyManager::get<DeferredLightingEffect>()->addPointLight(position, largestDiameter / 2.0f,
|
||||
color, intensity);
|
||||
}
|
||||
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
glm::vec4 color(diffuseR, diffuseG, diffuseB, 1.0f);
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireSphere(0.5f, 15, 15, color);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter());
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f));
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_RenderableLightEntityItem_h
|
||||
|
||||
#include <LightEntityItem.h>
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class RenderableLightEntityItem : public LightEntityItem {
|
||||
public:
|
||||
|
@ -27,6 +28,8 @@ public:
|
|||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
#include <DeferredLightingEffect.h>
|
||||
|
@ -23,32 +24,34 @@ EntityItemPointer RenderableLineEntityItem::factory(const EntityItemID& entityID
|
|||
return EntityItemPointer(new RenderableLineEntityItem(entityID, properties));
|
||||
}
|
||||
|
||||
void RenderableLineEntityItem::updateGeometry() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (_lineVerticesID == GeometryCache::UNKNOWN_ID) {
|
||||
_lineVerticesID = geometryCache ->allocateID();
|
||||
}
|
||||
if (_pointsChanged) {
|
||||
glm::vec4 lineColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
geometryCache->updateVertices(_lineVerticesID, getLinePoints(), lineColor);
|
||||
_pointsChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableLineEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableLineEntityItem::render");
|
||||
assert(getType() == EntityTypes::Line);
|
||||
// glm::vec3 position = getPosition();
|
||||
// glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
glm::vec4 lineColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
glPushMatrix();
|
||||
glLineWidth(getLineWidth());
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (_lineVerticesID == GeometryCache::UNKNOWN_ID) {
|
||||
_lineVerticesID = geometryCache ->allocateID();
|
||||
}
|
||||
//TODO: Figure out clean , efficient way to do relative line positioning. For now we'll just use absolute positioning.
|
||||
//glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
if (_pointsChanged) {
|
||||
geometryCache->updateVertices(_lineVerticesID, getLinePoints(), lineColor);
|
||||
_pointsChanged = false;
|
||||
}
|
||||
if (getLinePoints().size() > 1) {
|
||||
geometryCache->renderVertices(gpu::LINE_STRIP, _lineVerticesID);
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
Q_ASSERT(getType() == EntityTypes::Line);
|
||||
updateGeometry();
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
// TODO: Figure out clean , efficient way to do relative line positioning. For now we'll just use absolute positioning.
|
||||
//batch.setModelTransform(getTransformToCenter());
|
||||
batch.setModelTransform(Transform());
|
||||
|
||||
batch._glLineWidth(getLineWidth());
|
||||
if (getLinePoints().size() > 1) {
|
||||
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
|
||||
}
|
||||
batch._glLineWidth(1.0f);
|
||||
|
||||
RenderableDebugableEntityItem::render(this, args);
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <LineEntityItem.h>
|
||||
#include "RenderableDebugableEntityItem.h"
|
||||
#include "RenderableEntityItem.h"
|
||||
#include <GeometryCache.h>
|
||||
|
||||
class RenderableLineEntityItem : public LineEntityItem {
|
||||
|
@ -27,7 +28,11 @@ public:
|
|||
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
protected:
|
||||
void updateGeometry();
|
||||
|
||||
int _lineVerticesID;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <AbstractViewStateInterface.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <Model.h>
|
||||
#include <PerfStat.h>
|
||||
#include <render/Scene.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
#include "EntitiesRendererLogging.h"
|
||||
|
@ -108,6 +110,90 @@ void RenderableModelEntityItem::remapTextures() {
|
|||
_currentTextures = _textures;
|
||||
}
|
||||
|
||||
// TODO: we need a solution for changes to the postion/rotation/etc of a model...
|
||||
// this current code path only addresses that in this setup case... not the changing/moving case
|
||||
bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
|
||||
if (!_model && renderArgs) {
|
||||
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||
PerformanceTimer perfTimer("getModel");
|
||||
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(renderArgs->_renderer);
|
||||
getModel(renderer);
|
||||
}
|
||||
if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoadedWithTextures()) {
|
||||
_model->setScaleToFit(true, getDimensions());
|
||||
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
||||
_model->setRotation(getRotation());
|
||||
_model->setTranslation(getPosition());
|
||||
|
||||
// make sure to simulate so everything gets set up correctly for rendering
|
||||
{
|
||||
PerformanceTimer perfTimer("_model->simulate");
|
||||
_model->simulate(0.0f);
|
||||
}
|
||||
_needsInitialSimulation = false;
|
||||
|
||||
_model->renderSetup(renderArgs);
|
||||
}
|
||||
bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(renderArgs);
|
||||
return ready;
|
||||
}
|
||||
|
||||
class RenderableModelEntityItemMeta {
|
||||
public:
|
||||
RenderableModelEntityItemMeta(EntityItemPointer entity) : entity(entity){ }
|
||||
typedef render::Payload<RenderableModelEntityItemMeta> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
EntityItemPointer entity;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const RenderableModelEntityItemMeta::Pointer& payload) {
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
}
|
||||
|
||||
template <> const Item::Bound payloadGetBound(const RenderableModelEntityItemMeta::Pointer& payload) {
|
||||
if (payload && payload->entity) {
|
||||
return payload->entity->getAABox();
|
||||
}
|
||||
return render::Item::Bound();
|
||||
}
|
||||
template <> void payloadRender(const RenderableModelEntityItemMeta::Pointer& payload, RenderArgs* args) {
|
||||
if (args) {
|
||||
if (payload && payload->entity) {
|
||||
payload->entity->render(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
_myMetaItem = scene->allocateID();
|
||||
|
||||
auto renderData = RenderableModelEntityItemMeta::Pointer(new RenderableModelEntityItemMeta(self));
|
||||
auto renderPayload = render::PayloadPointer(new RenderableModelEntityItemMeta::Payload(renderData));
|
||||
|
||||
pendingChanges.resetItem(_myMetaItem, renderPayload);
|
||||
|
||||
if (_model) {
|
||||
return _model->addToScene(scene, pendingChanges);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) {
|
||||
pendingChanges.removeItem(_myMetaItem);
|
||||
if (_model) {
|
||||
_model->removeFromScene(scene, pendingChanges);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items, and it handles
|
||||
// the per frame simulation/update that might be required if the models properties changed.
|
||||
void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RMEIrender");
|
||||
assert(getType() == EntityTypes::Model);
|
||||
|
@ -124,10 +210,29 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
}
|
||||
|
||||
if (hasModel()) {
|
||||
if (_model) {
|
||||
if (QUrl(getModelURL()) != _model->getURL()) {
|
||||
qDebug() << "Updating model URL: " << getModelURL();
|
||||
_model->setURL(getModelURL());
|
||||
}
|
||||
|
||||
// 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 = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
render::PendingChanges pendingChanges;
|
||||
if (_model->needsFixupInScene()) {
|
||||
_model->removeFromScene(scene, pendingChanges);
|
||||
_model->addToScene(scene, pendingChanges);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
|
||||
_model->setVisibleInScene(getVisible(), scene);
|
||||
}
|
||||
|
||||
|
||||
remapTextures();
|
||||
glPushMatrix();
|
||||
{
|
||||
float alpha = getLocalRenderAlpha();
|
||||
// float alpha = getLocalRenderAlpha();
|
||||
|
||||
if (!_model || _needsModelReload) {
|
||||
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||
|
@ -167,23 +272,8 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
}
|
||||
_needsInitialSimulation = false;
|
||||
}
|
||||
|
||||
if (_model->isActive()) {
|
||||
// TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render
|
||||
// is significantly more expensive. Is there a way to call this that doesn't cost us as much?
|
||||
PerformanceTimer perfTimer("model->render");
|
||||
// filter out if not needed to render
|
||||
if (args && (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE)) {
|
||||
if (movingOrAnimating) {
|
||||
_model->renderInScene(alpha, args);
|
||||
}
|
||||
} else {
|
||||
_model->renderInScene(alpha, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
if (highlightSimulationOwnership) {
|
||||
glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
|
@ -199,6 +289,10 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
|||
|
||||
Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
||||
Model* result = NULL;
|
||||
|
||||
if (!renderer) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// make sure our renderer is setup
|
||||
if (!_myRenderer) {
|
||||
|
@ -206,7 +300,7 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
|||
}
|
||||
assert(_myRenderer == renderer); // you should only ever render on one renderer
|
||||
|
||||
if (QThread::currentThread() != _myRenderer->thread()) {
|
||||
if (!_myRenderer || QThread::currentThread() != _myRenderer->thread()) {
|
||||
return _model;
|
||||
}
|
||||
|
||||
|
@ -394,7 +488,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
// to the visual model and apply them to the collision model (without regard for the
|
||||
// collision model's extents).
|
||||
|
||||
glm::vec3 scale = _dimensions / renderGeometry.getUnscaledMeshExtents().size();
|
||||
glm::vec3 scale = getDimensions() / renderGeometry.getUnscaledMeshExtents().size();
|
||||
// multiply each point by scale before handing the point-set off to the physics engine.
|
||||
// also determine the extents of the collision model.
|
||||
AABox box;
|
||||
|
|
|
@ -43,6 +43,11 @@ public:
|
|||
|
||||
virtual void somethingChangedNotification() { _needsInitialSimulation = true; }
|
||||
|
||||
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr);
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
|
@ -71,6 +76,8 @@ private:
|
|||
QStringList _originalTextures;
|
||||
bool _originalTexturesRead;
|
||||
QVector<QVector<glm::vec3>> _points;
|
||||
|
||||
render::ItemID _myMetaItem;
|
||||
};
|
||||
|
||||
#endif // hifi_RenderableModelEntityItem_h
|
||||
|
|
|
@ -30,8 +30,7 @@ RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const Ent
|
|||
}
|
||||
|
||||
void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
|
||||
|
||||
assert(getType() == EntityTypes::ParticleEffect);
|
||||
Q_ASSERT(getType() == EntityTypes::ParticleEffect);
|
||||
PerformanceTimer perfTimer("RenderableParticleEffectEntityItem::render");
|
||||
|
||||
if (_texturesChangedFlag) {
|
||||
|
@ -45,143 +44,67 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
|
|||
_texturesChangedFlag = false;
|
||||
}
|
||||
|
||||
if (!_texture) {
|
||||
renderUntexturedQuads(args);
|
||||
} else if (_texture && !_texture->isLoaded()) {
|
||||
renderUntexturedQuads(args);
|
||||
} else {
|
||||
renderTexturedQuads(args);
|
||||
bool textured = _texture && _texture->isLoaded();
|
||||
updateQuads(args, textured);
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
if (textured) {
|
||||
batch.setUniformTexture(0, _texture->getGPUTexture());
|
||||
}
|
||||
batch.setModelTransform(getTransformToCenter());
|
||||
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::QUADS, _cacheID);
|
||||
};
|
||||
|
||||
void RenderableParticleEffectEntityItem::renderUntexturedQuads(RenderArgs* args) {
|
||||
|
||||
float particleRadius = getParticleRadius();
|
||||
|
||||
const float MAX_COLOR = 255.0f;
|
||||
glm::vec4 particleColor(getColor()[RED_INDEX] / MAX_COLOR,
|
||||
getColor()[GREEN_INDEX] / MAX_COLOR,
|
||||
getColor()[BLUE_INDEX] / MAX_COLOR,
|
||||
getLocalRenderAlpha());
|
||||
|
||||
glm::vec3 upOffset = args->_viewFrustum->getUp() * particleRadius;
|
||||
glm::vec3 rightOffset = args->_viewFrustum->getRight() * particleRadius;
|
||||
|
||||
QVector<glm::vec3> vertices(getLivingParticleCount() * VERTS_PER_PARTICLE);
|
||||
quint32 count = 0;
|
||||
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
|
||||
glm::vec3 pos = _particlePositions[i];
|
||||
|
||||
// generate corners of quad, aligned to face the camera
|
||||
vertices.append(pos - rightOffset + upOffset);
|
||||
vertices.append(pos + rightOffset + upOffset);
|
||||
vertices.append(pos + rightOffset - upOffset);
|
||||
vertices.append(pos - rightOffset - upOffset);
|
||||
count++;
|
||||
}
|
||||
|
||||
// just double checking, cause if this invarient is false, we might have memory corruption bugs.
|
||||
assert(count == getLivingParticleCount());
|
||||
|
||||
// update geometry cache with all the verts in model coordinates.
|
||||
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, particleColor);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::quat rotation = getRotation();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::vec3 positionToCenter = getCenter() - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderVertices(gpu::QUADS, _cacheID);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
static glm::vec3 zSortAxis;
|
||||
static bool zSort(const glm::vec3& rhs, const glm::vec3& lhs) {
|
||||
return glm::dot(rhs, ::zSortAxis) > glm::dot(lhs, ::zSortAxis);
|
||||
}
|
||||
|
||||
void RenderableParticleEffectEntityItem::renderTexturedQuads(RenderArgs* args) {
|
||||
|
||||
void RenderableParticleEffectEntityItem::updateQuads(RenderArgs* args, bool textured) {
|
||||
float particleRadius = getParticleRadius();
|
||||
|
||||
const float MAX_COLOR = 255.0f;
|
||||
glm::vec4 particleColor(getColor()[RED_INDEX] / MAX_COLOR,
|
||||
getColor()[GREEN_INDEX] / MAX_COLOR,
|
||||
getColor()[BLUE_INDEX] / MAX_COLOR,
|
||||
getLocalRenderAlpha());
|
||||
|
||||
QVector<glm::vec3> positions(getLivingParticleCount());
|
||||
quint32 count = 0;
|
||||
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
|
||||
positions.append(_particlePositions[i]);
|
||||
count++;
|
||||
}
|
||||
|
||||
// just double checking, cause if this invarient is false, we might have memory corruption bugs.
|
||||
assert(count == getLivingParticleCount());
|
||||
|
||||
// sort particles back to front
|
||||
::zSortAxis = args->_viewFrustum->getDirection();
|
||||
qSort(positions.begin(), positions.end(), zSort);
|
||||
|
||||
QVector<glm::vec3> vertices(getLivingParticleCount() * VERTS_PER_PARTICLE);
|
||||
QVector<glm::vec2> textureCoords(getLivingParticleCount() * VERTS_PER_PARTICLE);
|
||||
|
||||
glm::vec4 particleColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
|
||||
glm::vec3 upOffset = args->_viewFrustum->getUp() * particleRadius;
|
||||
glm::vec3 rightOffset = args->_viewFrustum->getRight() * particleRadius;
|
||||
|
||||
|
||||
QVector<glm::vec3> vertices;
|
||||
QVector<glm::vec3> positions;
|
||||
QVector<glm::vec2> textureCoords;
|
||||
vertices.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE);
|
||||
|
||||
if (textured) {
|
||||
positions.reserve(getLivingParticleCount());
|
||||
textureCoords.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE);
|
||||
|
||||
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
|
||||
positions.append(_particlePositions[i]);
|
||||
|
||||
textureCoords.append(glm::vec2(0, 1));
|
||||
textureCoords.append(glm::vec2(1, 1));
|
||||
textureCoords.append(glm::vec2(1, 0));
|
||||
textureCoords.append(glm::vec2(0, 0));
|
||||
}
|
||||
|
||||
// sort particles back to front
|
||||
::zSortAxis = args->_viewFrustum->getDirection();
|
||||
qSort(positions.begin(), positions.end(), zSort);
|
||||
}
|
||||
|
||||
for (int i = 0; i < positions.size(); i++) {
|
||||
glm::vec3 pos = positions[i];
|
||||
glm::vec3 pos = (textured) ? positions[i] : _particlePositions[i];
|
||||
|
||||
// generate corners of quad aligned to face the camera.
|
||||
vertices.append(pos - rightOffset + upOffset);
|
||||
vertices.append(pos + rightOffset + upOffset);
|
||||
vertices.append(pos + rightOffset - upOffset);
|
||||
vertices.append(pos - rightOffset - upOffset);
|
||||
|
||||
textureCoords.append(glm::vec2(0, 1));
|
||||
textureCoords.append(glm::vec2(1, 1));
|
||||
textureCoords.append(glm::vec2(1, 0));
|
||||
textureCoords.append(glm::vec2(0, 0));
|
||||
}
|
||||
|
||||
// update geometry cache with all the verts in model coordinates.
|
||||
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, textureCoords, particleColor);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, _texture->getID());
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::vec3 position = getPosition();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::quat rotation = getRotation();
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glm::vec3 positionToCenter = getCenter() - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderVertices(gpu::QUADS, _cacheID);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
if (textured) {
|
||||
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, textureCoords, particleColor);
|
||||
} else {
|
||||
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, particleColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <ParticleEffectEntityItem.h>
|
||||
#include <TextureCache.h>
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem {
|
||||
public:
|
||||
|
@ -20,8 +21,9 @@ public:
|
|||
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
void renderUntexturedQuads(RenderArgs* args);
|
||||
void renderTexturedQuads(RenderArgs* args);
|
||||
void updateQuads(RenderArgs* args, bool textured);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
|
|||
}
|
||||
|
||||
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
|
||||
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
|
||||
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
|
||||
switch (_voxelSurfaceStyle) {
|
||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
|
||||
return scale / 2.0f;
|
||||
|
@ -183,18 +183,18 @@ glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
|
|||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
|
||||
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
|
||||
glm::vec3 center = getCenter();
|
||||
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
|
||||
glm::vec3 center = getCenterPosition();
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
positionToCenter -= _dimensions * glm::vec3(0.5f, 0.5f, 0.5f) - getSurfacePositionAdjustment();
|
||||
positionToCenter -= getDimensions() * glm::vec3(0.5f, 0.5f, 0.5f) - getSurfacePositionAdjustment();
|
||||
glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
|
||||
glm::mat4 scaled = glm::scale(centerToCorner, scale);
|
||||
return scaled;
|
||||
}
|
||||
|
||||
glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const {
|
||||
glm::mat4 rotation = glm::mat4_cast(_rotation);
|
||||
glm::mat4 rotation = glm::mat4_cast(getRotation());
|
||||
glm::mat4 translation = glm::translate(getPosition());
|
||||
return translation * rotation * voxelToLocalMatrix();
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) {
|
|||
// if _voxelSurfaceStyle is SURFACE_EDGED_CUBIC, we maintain an extra layer of
|
||||
// voxels all around the requested voxel space. Having the empty voxels around
|
||||
// the edges changes how the surface extractor behaves.
|
||||
|
||||
|
||||
if (_voxelSurfaceStyle == SURFACE_EDGED_CUBIC) {
|
||||
return _volData->getVoxelAt(x + 1, y + 1, z + 1);
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ void RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toV
|
|||
if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint8_t uVoxelValue = getVoxel(x, y, z);
|
||||
if (toValue != 0) {
|
||||
if (uVoxelValue == 0) {
|
||||
|
@ -294,7 +294,7 @@ void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi
|
|||
void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) {
|
||||
// glm::vec3 centerVoxelCoords = worldToVoxelCoordinates(centerWorldCoords);
|
||||
glm::vec4 centerVoxelCoords = worldToVoxelMatrix() * glm::vec4(centerWorldCoords, 1.0f);
|
||||
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
|
||||
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
|
||||
float scaleY = scale.y;
|
||||
float radiusVoxelCoords = radiusWorldCoords / scaleY;
|
||||
setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue);
|
||||
|
@ -347,8 +347,8 @@ void RenderablePolyVoxEntityItem::getModel() {
|
|||
sizeof(PolyVox::PositionMaterialNormal),
|
||||
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// auto normalAttrib = mesh->getAttributeBuffer(gpu::Stream::NORMAL);
|
||||
// for (auto normal = normalAttrib.begin<glm::vec3>(); normal != normalAttrib.end<glm::vec3>(); normal++) {
|
||||
// (*normal) = -(*normal);
|
||||
|
@ -363,7 +363,7 @@ void RenderablePolyVoxEntityItem::getModel() {
|
|||
// gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::RAW)));
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
qDebug() << "---- vecIndices.size() =" << vecIndices.size();
|
||||
qDebug() << "---- vecVertices.size() =" << vecVertices.size();
|
||||
|
@ -380,22 +380,25 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
|||
getModel();
|
||||
}
|
||||
|
||||
glPushMatrix();
|
||||
glm::mat4 m = voxelToWorldMatrix();
|
||||
glMultMatrixf(&m[0][0]);
|
||||
Transform transform;
|
||||
transform.setTranslation(getPosition() - getRegistrationPoint() * getDimensions());
|
||||
transform.setRotation(getRotation());
|
||||
transform.setScale(getDimensions() / _voxelVolumeSize);
|
||||
|
||||
auto mesh = _modelGeometry.getMesh();
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
|
||||
batch.setModelTransform(transform);
|
||||
batch.setInputFormat(mesh->getVertexFormat());
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer());
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL,
|
||||
mesh->getVertexBuffer()._buffer,
|
||||
sizeof(float) * 3,
|
||||
mesh->getVertexBuffer()._stride);
|
||||
batch.setIndexBuffer(gpu::UINT32, mesh->getIndexBuffer()._buffer, 0);
|
||||
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
|
||||
|
||||
auto mesh = _modelGeometry.getMesh();
|
||||
gpu::Batch batch;
|
||||
batch.setInputFormat(mesh->getVertexFormat());
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer());
|
||||
batch.setInputBuffer(gpu::Stream::NORMAL,
|
||||
mesh->getVertexBuffer()._buffer,
|
||||
sizeof(float) * 3,
|
||||
mesh->getVertexBuffer()._stride);
|
||||
batch.setIndexBuffer(gpu::UINT32, mesh->getIndexBuffer()._buffer, 0);
|
||||
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
|
||||
gpu::GLBackend::renderBatch(batch);
|
||||
glPopMatrix();
|
||||
RenderableDebugableEntityItem::render(this, args);
|
||||
}
|
||||
|
||||
|
@ -444,17 +447,15 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
|||
glm::mat4 wtvMatrix = worldToVoxelMatrix();
|
||||
glm::vec3 normDirection = glm::normalize(direction);
|
||||
|
||||
// set ray cast length to long enough to cover all of the voxel space
|
||||
float distanceToEntity = glm::distance(origin, _position);
|
||||
float largestDimension = glm::max(_dimensions.x, _dimensions.y, _dimensions.z) * 2.0f;
|
||||
|
||||
// the PolyVox ray intersection code requires a near and far point.
|
||||
// set ray cast length to long enough to cover all of the voxel space
|
||||
float distanceToEntity = glm::distance(origin, getPosition());
|
||||
float largestDimension = glm::max(getDimensions().x, getDimensions().y, getDimensions().z) * 2.0f;
|
||||
glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension);
|
||||
|
||||
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
|
||||
glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f);
|
||||
|
||||
|
||||
PolyVox::Vector3DFloat startPoint(originInVoxel.x, originInVoxel.y, originInVoxel.z);
|
||||
// PolyVox::Vector3DFloat pvDirection(directionInVoxel.x, directionInVoxel.y, directionInVoxel.z);
|
||||
PolyVox::Vector3DFloat endPoint(farInVoxel.x, farInVoxel.y, farInVoxel.z);
|
||||
|
||||
PolyVox::RaycastResult raycastResult;
|
||||
|
@ -477,7 +478,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
|||
}
|
||||
|
||||
result -= glm::vec4(0.5f, 0.5f, 0.5f, 0.0f);
|
||||
|
||||
|
||||
glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * result;
|
||||
|
||||
distance = glm::distance(glm::vec3(intersectedWorldPosition), origin);
|
||||
|
@ -554,9 +555,9 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
|||
<< voxelXSize << voxelYSize << voxelZSize;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int rawSize = voxelXSize * voxelYSize * voxelZSize;
|
||||
|
||||
|
||||
QByteArray compressedData;
|
||||
reader >> compressedData;
|
||||
QByteArray uncompressedData = qUncompress(compressedData);
|
||||
|
@ -633,9 +634,6 @@ void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
float offL = -0.5f;
|
||||
float offH = 0.5f;
|
||||
|
||||
// float offL = 0.0f;
|
||||
// float offH = 1.0f;
|
||||
|
||||
glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f));
|
||||
glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f));
|
||||
glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f));
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "PolyVoxEntityItem.h"
|
||||
#include "RenderableDebugableEntityItem.h"
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class RenderablePolyVoxEntityItem : public PolyVoxEntityItem {
|
||||
public:
|
||||
|
@ -70,6 +71,8 @@ public:
|
|||
virtual void setAll(uint8_t toValue);
|
||||
|
||||
virtual void setVoxelInVolume(glm::vec3 position, uint8_t toValue);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
private:
|
||||
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
|
@ -25,35 +26,17 @@ EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entity
|
|||
|
||||
void RenderableSphereEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableSphereEntityItem::render");
|
||||
assert(getType() == EntityTypes::Sphere);
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 center = getCenter();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
|
||||
const float MAX_COLOR = 255.0f;
|
||||
glm::vec4 sphereColor(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR,
|
||||
getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha());
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
|
||||
glPushMatrix();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
|
||||
// TODO: it would be cool to select different slices/stacks geometry based on the size of the sphere
|
||||
// and the distance to the viewer. This would allow us to reduce the triangle count for smaller spheres
|
||||
// that aren't close enough to see the tessellation and use larger triangle count for spheres that would
|
||||
// expose that effect
|
||||
const int SLICES = 15;
|
||||
const int STACKS = 15;
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(0.5f, SLICES, STACKS, sphereColor);
|
||||
glPopMatrix();
|
||||
glPopMatrix();
|
||||
Q_ASSERT(getType() == EntityTypes::Sphere);
|
||||
glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
|
||||
// TODO: it would be cool to select different slices/stacks geometry based on the size of the sphere
|
||||
// and the distance to the viewer. This would allow us to reduce the triangle count for smaller spheres
|
||||
// that aren't close enough to see the tessellation and use larger triangle count for spheres that would
|
||||
// expose that effect
|
||||
const int SLICES = 15, STACKS = 15;
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter());
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor);
|
||||
};
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include <SphereEntityItem.h>
|
||||
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class RenderableSphereEntityItem : public SphereEntityItem {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
@ -23,6 +25,8 @@ public:
|
|||
{ }
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -16,64 +16,44 @@
|
|||
#include <DeferredLightingEffect.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <PerfStat.h>
|
||||
#include <TextRenderer.h>
|
||||
|
||||
#include "RenderableTextEntityItem.h"
|
||||
#include "GLMHelpers.h"
|
||||
|
||||
const int FIXED_FONT_POINT_SIZE = 40;
|
||||
|
||||
EntityItemPointer RenderableTextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
return EntityItemPointer(new RenderableTextEntityItem(entityID, properties));
|
||||
}
|
||||
|
||||
void RenderableTextEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableTextEntityItem::render");
|
||||
assert(getType() == EntityTypes::Text);
|
||||
glm::vec3 position = getPosition();
|
||||
Q_ASSERT(getType() == EntityTypes::Text);
|
||||
|
||||
static const float SLIGHTLY_BEHIND = -0.005f;
|
||||
glm::vec4 textColor = glm::vec4(toGlm(getTextColorX()), 1.0f);
|
||||
glm::vec4 backgroundColor = glm::vec4(toGlm(getBackgroundColorX()), 1.0f);
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::vec3 halfDimensions = dimensions / 2.0f;
|
||||
glm::quat rotation = getRotation();
|
||||
float leftMargin = 0.1f;
|
||||
float topMargin = 0.1f;
|
||||
|
||||
//qCDebug(entitytree) << "RenderableTextEntityItem::render() id:" << getEntityItemID() << "text:" << getText();
|
||||
|
||||
glPushMatrix();
|
||||
{
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
float alpha = 1.0f; //getBackgroundAlpha();
|
||||
static const float SLIGHTLY_BEHIND = -0.005f;
|
||||
|
||||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
|
||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
|
||||
|
||||
// TODO: Determine if we want these entities to have the deferred lighting effect? I think we do, so that the color
|
||||
// used for a sphere, or box have the same look as those used on a text entity.
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram();
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, glm::vec4(toGlm(getBackgroundColorX()), alpha));
|
||||
DependencyManager::get<DeferredLightingEffect>()->releaseSimpleProgram();
|
||||
|
||||
TextRenderer* textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE / 2.0f);
|
||||
|
||||
glTranslatef(-(halfDimensions.x - leftMargin), halfDimensions.y - topMargin, 0.0f);
|
||||
glm::vec4 textColor(toGlm(getTextColorX()), alpha);
|
||||
// this is a ratio determined through experimentation
|
||||
const float scaleFactor = 0.08f * _lineHeight;
|
||||
glScalef(scaleFactor, -scaleFactor, scaleFactor);
|
||||
glm::vec2 bounds(dimensions.x / scaleFactor, dimensions.y / scaleFactor);
|
||||
textRenderer->draw(0, 0, _text, textColor, bounds);
|
||||
}
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
void RenderableTextEntityItem::enableClipPlane(GLenum plane, float x, float y, float z, float w) {
|
||||
GLdouble coefficients[] = { x, y, z, w };
|
||||
glClipPlane(plane, coefficients);
|
||||
glEnable(plane);
|
||||
|
||||
Transform transformToTopLeft = getTransformToCenter();
|
||||
transformToTopLeft.postTranslate(glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left
|
||||
transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed
|
||||
|
||||
// Batch render calls
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(transformToTopLeft);
|
||||
|
||||
// Render background
|
||||
glm::vec3 minCorner = glm::vec3(0.0f, -dimensions.y, SLIGHTLY_BEHIND);
|
||||
glm::vec3 maxCorner = glm::vec3(dimensions.x, 0.0f, SLIGHTLY_BEHIND);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderQuad(batch, minCorner, maxCorner, backgroundColor);
|
||||
|
||||
float scale = _lineHeight / _textRenderer->getRowHeight();
|
||||
transformToTopLeft.setScale(scale); // Scale to have the correct line height
|
||||
batch.setModelTransform(transformToTopLeft);
|
||||
|
||||
float leftMargin = 0.5f * _lineHeight, topMargin = 0.5f * _lineHeight;
|
||||
glm::vec2 bounds = glm::vec2(dimensions.x - 2.0f * leftMargin, dimensions.y - 2.0f * topMargin);
|
||||
_textRenderer->draw(batch, leftMargin / scale, -topMargin / scale, _text, textColor, bounds / scale);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
#define hifi_RenderableTextEntityItem_h
|
||||
|
||||
#include <TextEntityItem.h>
|
||||
#include <TextRenderer3D.h>
|
||||
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
const int FIXED_FONT_POINT_SIZE = 40;
|
||||
|
||||
class RenderableTextEntityItem : public TextEntityItem {
|
||||
public:
|
||||
|
@ -21,12 +26,14 @@ public:
|
|||
RenderableTextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||
TextEntityItem(entityItemID, properties)
|
||||
{ }
|
||||
~RenderableTextEntityItem() { delete _textRenderer; }
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
private:
|
||||
void enableClipPlane(GLenum plane, float x, float y, float z, float w);
|
||||
|
||||
TextRenderer3D* _textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE / 2.0f);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -142,10 +142,10 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
|||
glm::vec3 point = intersection.intersection;
|
||||
point -= getPosition();
|
||||
point = glm::inverse(getRotation()) * point;
|
||||
point /= _dimensions;
|
||||
point /= getDimensions();
|
||||
point += 0.5f;
|
||||
point.y = 1.0f - point.y;
|
||||
point *= _dimensions * METERS_TO_INCHES * DPI;
|
||||
point *= getDimensions() * METERS_TO_INCHES * DPI;
|
||||
// Forward the mouse event.
|
||||
QMouseEvent mappedEvent(event->type(),
|
||||
QPoint((int)point.x, (int)point.y),
|
||||
|
@ -161,7 +161,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
|||
QObject::connect(renderer, &EntityTreeRenderer::mouseMoveOnEntity, forwardMouseEvent);
|
||||
}
|
||||
|
||||
glm::vec2 dims = glm::vec2(_dimensions);
|
||||
glm::vec2 dims = glm::vec2(getDimensions());
|
||||
dims *= METERS_TO_INCHES * DPI;
|
||||
// The offscreen surface is idempotent for resizes (bails early
|
||||
// if it's a no-op), so it's safe to just call resize every frame
|
||||
|
@ -169,43 +169,30 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
|||
_webSurface->resize(QSize(dims.x, dims.y));
|
||||
currentContext->makeCurrent(currentSurface);
|
||||
|
||||
Glower glow(0);
|
||||
Glower glow(0.0f);
|
||||
PerformanceTimer perfTimer("RenderableWebEntityItem::render");
|
||||
assert(getType() == EntityTypes::Web);
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::vec3 halfDimensions = dimensions / 2.0f;
|
||||
glm::quat rotation = getRotation();
|
||||
Q_ASSERT(getType() == EntityTypes::Web);
|
||||
static const glm::vec2 texMin(0.0f);
|
||||
static const glm::vec2 texMax(1.0f);
|
||||
glm::vec2 topLeft(-0.5f -0.5f);
|
||||
glm::vec2 bottomRight(0.5f, 0.5f);
|
||||
|
||||
glPushMatrix();
|
||||
{
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
static const glm::vec2 texMin(0);
|
||||
static const glm::vec2 texMax(1);
|
||||
glm::vec2 topLeft(-halfDimensions.x, -halfDimensions.y);
|
||||
glm::vec2 bottomRight(halfDimensions.x, halfDimensions.y);
|
||||
if (_texture) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(
|
||||
topLeft, bottomRight, texMin, texMax, glm::vec4(1));
|
||||
if (_texture) {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter());
|
||||
if (_texture) {
|
||||
batch._glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
glPopMatrix();
|
||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, true);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f));
|
||||
DependencyManager::get<DeferredLightingEffect>()->releaseSimpleProgram(batch);
|
||||
}
|
||||
|
||||
void RenderableWebEntityItem::setSourceUrl(const QString& value) {
|
||||
qDebug() << "Setting web entity source URL to " << value;
|
||||
if (_sourceUrl != value) {
|
||||
qDebug() << "Setting web entity source URL to " << value;
|
||||
_sourceUrl = value;
|
||||
if (_webSurface) {
|
||||
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <WebEntityItem.h>
|
||||
|
||||
#include "RenderableEntityItem.h"
|
||||
|
||||
class OffscreenQmlSurface;
|
||||
|
||||
class RenderableWebEntityItem : public WebEntityItem {
|
||||
|
@ -25,6 +27,8 @@ public:
|
|||
virtual void render(RenderArgs* args);
|
||||
virtual void setSourceUrl(const QString& value);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
private:
|
||||
OffscreenQmlSurface* _webSurface{ nullptr };
|
||||
QMetaObject::Connection _connection;
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
|
||||
#include "RenderableZoneEntityItem.h"
|
||||
|
||||
#include <gpu/GPUConfig.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
|
@ -90,49 +93,37 @@ void RenderableZoneEntityItem::updateGeometry() {
|
|||
}
|
||||
|
||||
void RenderableZoneEntityItem::render(RenderArgs* args) {
|
||||
Q_ASSERT(getType() == EntityTypes::Zone);
|
||||
|
||||
if (_drawZoneBoundaries) {
|
||||
switch (getShapeType()) {
|
||||
case SHAPE_TYPE_COMPOUND: {
|
||||
PerformanceTimer perfTimer("zone->renderCompound");
|
||||
updateGeometry();
|
||||
|
||||
if (_model && _model->isActive()) {
|
||||
PerformanceTimer perfTimer("zone->renderCompound");
|
||||
glPushMatrix();
|
||||
_model->renderInScene(getLocalRenderAlpha(), args);
|
||||
glPopMatrix();
|
||||
// FIX ME: this is no longer available... we need to switch to payloads
|
||||
//_model->renderInScene(getLocalRenderAlpha(), args);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHAPE_TYPE_BOX:
|
||||
case SHAPE_TYPE_SPHERE: {
|
||||
PerformanceTimer perfTimer("zone->renderPrimitive");
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 center = getCenter();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
glm::vec4 DEFAULT_COLOR(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
glm::vec4 DEFAULT_COLOR(1.0f, 1.0f, 1.0f, getLocalRenderAlpha());
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter());
|
||||
|
||||
glPushMatrix(); {
|
||||
glTranslatef(position.x, position.y, position.z);
|
||||
glm::vec3 axis = glm::axis(rotation);
|
||||
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
|
||||
glPushMatrix(); {
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
|
||||
glScalef(dimensions.x, dimensions.y, dimensions.z);
|
||||
|
||||
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
|
||||
|
||||
if (getShapeType() == SHAPE_TYPE_SPHERE) {
|
||||
const int SLICES = 15;
|
||||
const int STACKS = 15;
|
||||
deferredLightingEffect->renderWireSphere(0.5f, SLICES, STACKS, DEFAULT_COLOR);
|
||||
} else {
|
||||
deferredLightingEffect->renderWireCube(1.0f, DEFAULT_COLOR);
|
||||
}
|
||||
} glPopMatrix();
|
||||
} glPopMatrix();
|
||||
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
|
||||
|
||||
if (getShapeType() == SHAPE_TYPE_SPHERE) {
|
||||
const int SLICES = 15, STACKS = 15;
|
||||
deferredLightingEffect->renderWireSphere(batch, 0.5f, SLICES, STACKS, DEFAULT_COLOR);
|
||||
} else {
|
||||
deferredLightingEffect->renderWireCube(batch, 1.0f, DEFAULT_COLOR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -14,3 +14,4 @@ target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
|
|||
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
|
||||
|
||||
link_hifi_libraries(avatars shared octree gpu model fbx networking animation environment)
|
||||
include_hifi_library_headers(render)
|
||||
|
|
|
@ -101,8 +101,8 @@ void BoxEntityItem::debugDump() const {
|
|||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << " BOX EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
|
||||
qCDebug(entities) << " position:" << debugTreeVector(_position);
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions);
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
|||
_lastEditedFromRemoteInRemoteTime(0),
|
||||
_created(UNKNOWN_CREATED_TIME),
|
||||
_changedOnServer(0),
|
||||
_position(ENTITY_ITEM_ZERO_VEC3),
|
||||
_dimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS),
|
||||
_rotation(ENTITY_ITEM_DEFAULT_ROTATION),
|
||||
_transform(ENTITY_ITEM_DEFAULT_ROTATION,
|
||||
ENTITY_ITEM_DEFAULT_DIMENSIONS,
|
||||
ENTITY_ITEM_DEFAULT_POSITION),
|
||||
_glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL),
|
||||
_localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA),
|
||||
_density(ENTITY_ITEM_DEFAULT_DENSITY),
|
||||
|
@ -334,8 +334,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
}
|
||||
|
||||
// if this bitstream indicates that this node is the simulation owner, ignore any physics-related updates.
|
||||
glm::vec3 savePosition = _position;
|
||||
glm::quat saveRotation = _rotation;
|
||||
glm::vec3 savePosition = getPosition();
|
||||
glm::quat saveRotation = getRotation();
|
||||
glm::vec3 saveVelocity = _velocity;
|
||||
glm::vec3 saveAngularVelocity = _angularVelocity;
|
||||
|
||||
|
@ -613,8 +613,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
if (_simulatorID == myNodeID && !_simulatorID.isNull()) {
|
||||
// we own the simulation, so we keep our transform+velocities and remove any related dirty flags
|
||||
// rather than accept the values in the packet
|
||||
_position = savePosition;
|
||||
_rotation = saveRotation;
|
||||
setPosition(savePosition);
|
||||
setRotation(saveRotation);
|
||||
_velocity = saveVelocity;
|
||||
_angularVelocity = saveAngularVelocity;
|
||||
_dirtyFlags &= ~(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES);
|
||||
|
@ -627,10 +627,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
}
|
||||
|
||||
void EntityItem::debugDump() const {
|
||||
auto position = getPosition();
|
||||
qCDebug(entities) << "EntityItem id:" << getEntityItemID();
|
||||
qCDebug(entities, " edited ago:%f", getEditedAgo());
|
||||
qCDebug(entities, " position:%f,%f,%f", _position.x, _position.y, _position.z);
|
||||
qCDebug(entities) << " dimensions:" << _dimensions;
|
||||
qCDebug(entities, " position:%f,%f,%f", position.x, position.y, position.z);
|
||||
qCDebug(entities) << " dimensions:" << getDimensions();
|
||||
}
|
||||
|
||||
// adjust any internal timestamps to fix clock skew for this server
|
||||
|
@ -643,7 +644,6 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
|
|||
// lastEdited
|
||||
quint64 lastEditedInLocalTime;
|
||||
memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime));
|
||||
assert(lastEditedInLocalTime > 0);
|
||||
quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew;
|
||||
memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
|
||||
#ifdef WANT_DEBUG
|
||||
|
@ -652,10 +652,11 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
|
|||
qCDebug(entities) << " clockSkew: " << clockSkew;
|
||||
qCDebug(entities) << " lastEditedInServerTime: " << lastEditedInServerTime;
|
||||
#endif
|
||||
//assert(lastEditedInLocalTime > (quint64)0);
|
||||
}
|
||||
|
||||
float EntityItem::computeMass() const {
|
||||
return _density * _volumeMultiplier * _dimensions.x * _dimensions.y * _dimensions.z;
|
||||
float EntityItem::computeMass() const {
|
||||
return _density * _volumeMultiplier * getDimensions().x * getDimensions().y * getDimensions().z;
|
||||
}
|
||||
|
||||
void EntityItem::setDensity(float density) {
|
||||
|
@ -680,8 +681,8 @@ void EntityItem::setMass(float mass) {
|
|||
// Setting the mass actually changes the _density (at fixed volume), however
|
||||
// we must protect the density range to help maintain stability of physics simulation
|
||||
// therefore this method might not accept the mass that is supplied.
|
||||
|
||||
float volume = _volumeMultiplier * _dimensions.x * _dimensions.y * _dimensions.z;
|
||||
|
||||
float volume = _volumeMultiplier * getDimensions().x * getDimensions().y * getDimensions().z;
|
||||
|
||||
// compute new density
|
||||
const float MIN_VOLUME = 1.0e-6f; // 0.001mm^3
|
||||
|
@ -912,9 +913,9 @@ EntityItemProperties EntityItem::getProperties() const {
|
|||
|
||||
void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const {
|
||||
// a TerseUpdate includes the transform and its derivatives
|
||||
properties._position = _position;
|
||||
properties._position = getPosition();
|
||||
properties._velocity = _velocity;
|
||||
properties._rotation = _rotation;
|
||||
properties._rotation = getRotation();
|
||||
properties._angularVelocity = _angularVelocity;
|
||||
properties._acceleration = _acceleration;
|
||||
|
||||
|
@ -1003,10 +1004,37 @@ void EntityItem::recordCreationTime() {
|
|||
_lastSimulated = now;
|
||||
}
|
||||
|
||||
void EntityItem::setCenterPosition(const glm::vec3& position) {
|
||||
Transform transformToCenter = getTransformToCenter();
|
||||
transformToCenter.setTranslation(position);
|
||||
setTranformToCenter(transformToCenter);
|
||||
}
|
||||
|
||||
// TODO: doesn't this need to handle rotation?
|
||||
glm::vec3 EntityItem::getCenter() const {
|
||||
return _position + (_dimensions * (glm::vec3(0.5f,0.5f,0.5f) - _registrationPoint));
|
||||
const Transform EntityItem::getTransformToCenter() const {
|
||||
Transform result = getTransform();
|
||||
if (getRegistrationPoint() != ENTITY_ITEM_HALF_VEC3) { // If it is not already centered, translate to center
|
||||
result.postTranslate(ENTITY_ITEM_HALF_VEC3 - getRegistrationPoint()); // Position to center
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void EntityItem::setTranformToCenter(const Transform& transform) {
|
||||
if (getRegistrationPoint() == ENTITY_ITEM_HALF_VEC3) {
|
||||
// If it is already centered, just call setTransform
|
||||
setTransform(transform);
|
||||
return;
|
||||
}
|
||||
|
||||
Transform copy = transform;
|
||||
copy.postTranslate(getRegistrationPoint() - ENTITY_ITEM_HALF_VEC3); // Center to position
|
||||
setTransform(copy);
|
||||
}
|
||||
|
||||
void EntityItem::setDimensions(const glm::vec3& value) {
|
||||
if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
_transform.setScale(value);
|
||||
}
|
||||
|
||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||
|
@ -1014,13 +1042,13 @@ glm::vec3 EntityItem::getCenter() const {
|
|||
///
|
||||
AACube EntityItem::getMaximumAACube() const {
|
||||
// * we know that the position is the center of rotation
|
||||
glm::vec3 centerOfRotation = _position; // also where _registration point is
|
||||
glm::vec3 centerOfRotation = getPosition(); // also where _registration point is
|
||||
|
||||
// * we know that the registration point is the center of rotation
|
||||
// * we can calculate the length of the furthest extent from the registration point
|
||||
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
|
||||
glm::vec3 registrationPoint = (_dimensions * _registrationPoint);
|
||||
glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint));
|
||||
glm::vec3 registrationPoint = (getDimensions() * getRegistrationPoint());
|
||||
glm::vec3 registrationRemainder = (getDimensions() * (glm::vec3(1.0f, 1.0f, 1.0f) - getRegistrationPoint()));
|
||||
glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder);
|
||||
|
||||
// * we know that if you rotate in any direction you would create a sphere
|
||||
|
@ -1042,13 +1070,13 @@ AACube EntityItem::getMinimumAACube() const {
|
|||
// _position represents the position of the registration point.
|
||||
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
|
||||
|
||||
glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
|
||||
glm::vec3 unrotatedMinRelativeToEntity = - (getDimensions() * getRegistrationPoint());
|
||||
glm::vec3 unrotatedMaxRelativeToEntity = getDimensions() * registrationRemainder;
|
||||
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
|
||||
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
|
||||
|
||||
// shift the extents to be relative to the position/registration point
|
||||
rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position);
|
||||
rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition());
|
||||
|
||||
// the cube that best encompasses extents is...
|
||||
AABox box(rotatedExtentsRelativeToRegistrationPoint);
|
||||
|
@ -1066,13 +1094,13 @@ AABox EntityItem::getAABox() const {
|
|||
// _position represents the position of the registration point.
|
||||
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;
|
||||
|
||||
glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint);
|
||||
glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder;
|
||||
glm::vec3 unrotatedMinRelativeToEntity = - (getDimensions() * _registrationPoint);
|
||||
glm::vec3 unrotatedMaxRelativeToEntity = getDimensions() * registrationRemainder;
|
||||
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
|
||||
Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
|
||||
|
||||
// shift the extents to be relative to the position/registration point
|
||||
rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position);
|
||||
rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition());
|
||||
|
||||
return AABox(rotatedExtentsRelativeToRegistrationPoint);
|
||||
}
|
||||
|
@ -1093,7 +1121,7 @@ AABox EntityItem::getAABox() const {
|
|||
void EntityItem::setRadius(float value) {
|
||||
float diameter = value * 2.0f;
|
||||
float maxDimension = sqrt((diameter * diameter) / 3.0f);
|
||||
_dimensions = glm::vec3(maxDimension, maxDimension, maxDimension);
|
||||
setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
|
||||
}
|
||||
|
||||
// TODO: get rid of all users of this function...
|
||||
|
@ -1101,7 +1129,7 @@ void EntityItem::setRadius(float value) {
|
|||
// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2)
|
||||
// ... radius = sqrt(3 x maxDimension ^ 2) / 2.0f;
|
||||
float EntityItem::getRadius() const {
|
||||
return 0.5f * glm::length(_dimensions);
|
||||
return 0.5f * glm::length(getDimensions());
|
||||
}
|
||||
|
||||
bool EntityItem::contains(const glm::vec3& point) const {
|
||||
|
@ -1119,10 +1147,10 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
}
|
||||
|
||||
void EntityItem::updatePosition(const glm::vec3& value) {
|
||||
auto delta = glm::distance(_position, value);
|
||||
auto delta = glm::distance(getPosition(), value);
|
||||
if (delta > IGNORE_POSITION_DELTA) {
|
||||
_dirtyFlags |= EntityItem::DIRTY_POSITION;
|
||||
_position = value;
|
||||
setPosition(value);
|
||||
if (delta > ACTIVATION_POSITION_DELTA) {
|
||||
_dirtyFlags |= EntityItem::DIRTY_PHYSICS_ACTIVATION;
|
||||
}
|
||||
|
@ -1130,9 +1158,9 @@ void EntityItem::updatePosition(const glm::vec3& value) {
|
|||
}
|
||||
|
||||
void EntityItem::updateDimensions(const glm::vec3& value) {
|
||||
auto delta = glm::distance(_dimensions, value);
|
||||
auto delta = glm::distance(getDimensions(), value);
|
||||
if (delta > IGNORE_DIMENSIONS_DELTA) {
|
||||
_dimensions = value;
|
||||
setDimensions(value);
|
||||
if (delta > ACTIVATION_DIMENSIONS_DELTA) {
|
||||
// rebuilding the shape will always activate
|
||||
_dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS);
|
||||
|
@ -1141,10 +1169,10 @@ void EntityItem::updateDimensions(const glm::vec3& value) {
|
|||
}
|
||||
|
||||
void EntityItem::updateRotation(const glm::quat& rotation) {
|
||||
if (_rotation != rotation) {
|
||||
_rotation = rotation;
|
||||
if (getRotation() != rotation) {
|
||||
setRotation(rotation);
|
||||
|
||||
auto alignmentDot = glm::abs(glm::dot(_rotation, rotation));
|
||||
auto alignmentDot = glm::abs(glm::dot(getRotation(), rotation));
|
||||
if (alignmentDot < IGNORE_ALIGNMENT_DOT) {
|
||||
_dirtyFlags |= EntityItem::DIRTY_ROTATION;
|
||||
}
|
||||
|
@ -1159,7 +1187,7 @@ void EntityItem::updateMass(float mass) {
|
|||
// we must protect the density range to help maintain stability of physics simulation
|
||||
// therefore this method might not accept the mass that is supplied.
|
||||
|
||||
float volume = _volumeMultiplier * _dimensions.x * _dimensions.y * _dimensions.z;
|
||||
float volume = _volumeMultiplier * getDimensions().x * getDimensions().y * getDimensions().z;
|
||||
|
||||
// compute new density
|
||||
float newDensity = _density;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef hifi_EntityItem_h
|
||||
#define hifi_EntityItem_h
|
||||
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include <OctreeElement.h> // for OctreeElement::AppendState
|
||||
#include <OctreePacketData.h>
|
||||
#include <ShapeInfo.h>
|
||||
#include <Transform.h>
|
||||
|
||||
#include "EntityItemID.h"
|
||||
#include "EntityItemProperties.h"
|
||||
|
@ -33,6 +35,11 @@ class EntitySimulation;
|
|||
class EntityTreeElement;
|
||||
class EntityTreeElementExtraEncodeData;
|
||||
|
||||
namespace render {
|
||||
class Scene;
|
||||
class PendingChanges;
|
||||
}
|
||||
|
||||
// these thesholds determine what updates will be ignored (client and server)
|
||||
const float IGNORE_POSITION_DELTA = 0.0001f;
|
||||
const float IGNORE_DIMENSIONS_DELTA = 0.0005f;
|
||||
|
@ -151,6 +158,10 @@ public:
|
|||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData)
|
||||
{ return 0; }
|
||||
|
||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) { return false; } // by default entity items don't add to scene
|
||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges) { } // by default entity items don't add to scene
|
||||
virtual void render(RenderArgs* args) { } // by default entity items don't know how to render
|
||||
|
||||
static int expectedBytes();
|
||||
|
@ -176,19 +187,26 @@ public:
|
|||
|
||||
// attributes applicable to all entity types
|
||||
EntityTypes::EntityType getType() const { return _type; }
|
||||
const glm::vec3& getPosition() const { return _position; } /// get position in meters
|
||||
|
||||
void setPosition(const glm::vec3& value) { _position = value; }
|
||||
|
||||
glm::vec3 getCenter() const;
|
||||
|
||||
const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in meters
|
||||
|
||||
/// set dimensions in meter units (0.0 - TREE_SCALE)
|
||||
virtual void setDimensions(const glm::vec3& value) { _dimensions = glm::abs(value); }
|
||||
|
||||
const glm::quat& getRotation() const { return _rotation; }
|
||||
void setRotation(const glm::quat& rotation) { _rotation = rotation; }
|
||||
|
||||
inline glm::vec3 getCenterPosition() const { return getTransformToCenter().getTranslation(); }
|
||||
void setCenterPosition(const glm::vec3& position);
|
||||
|
||||
const Transform getTransformToCenter() const;
|
||||
void setTranformToCenter(const Transform& transform);
|
||||
|
||||
inline const Transform& getTransform() const { return _transform; }
|
||||
inline void setTransform(const Transform& transform) { _transform = transform; }
|
||||
|
||||
/// Position in meters (0.0 - TREE_SCALE)
|
||||
inline const glm::vec3& getPosition() const { return _transform.getTranslation(); }
|
||||
inline void setPosition(const glm::vec3& value) { _transform.setTranslation(value); }
|
||||
|
||||
inline const glm::quat& getRotation() const { return _transform.getRotation(); }
|
||||
inline void setRotation(const glm::quat& rotation) { _transform.setRotation(rotation); }
|
||||
|
||||
/// Dimensions in meters (0.0 - TREE_SCALE)
|
||||
inline const glm::vec3& getDimensions() const { return _transform.getScale(); }
|
||||
virtual void setDimensions(const glm::vec3& value);
|
||||
|
||||
float getGlowLevel() const { return _glowLevel; }
|
||||
void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; }
|
||||
|
@ -301,7 +319,7 @@ public:
|
|||
|
||||
virtual bool isReadyToComputeShape() { return true; }
|
||||
virtual void computeShapeInfo(ShapeInfo& info);
|
||||
virtual float getVolumeEstimate() const { return _dimensions.x * _dimensions.y * _dimensions.z; }
|
||||
virtual float getVolumeEstimate() const { return getDimensions().x * getDimensions().y * getDimensions().z; }
|
||||
|
||||
/// return preferred shape type (actual physical shape may differ)
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; }
|
||||
|
@ -368,9 +386,7 @@ protected:
|
|||
quint64 _created;
|
||||
quint64 _changedOnServer;
|
||||
|
||||
glm::vec3 _position;
|
||||
glm::vec3 _dimensions;
|
||||
glm::quat _rotation;
|
||||
Transform _transform;
|
||||
float _glowLevel;
|
||||
float _localRenderAlpha;
|
||||
float _density = ENTITY_ITEM_DEFAULT_DENSITY; // kg/m^3
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
// There is a minor performance gain when comparing/copying an existing glm::vec3 rather than
|
||||
// creating a new one on the stack so we declare the ZERO_VEC3 constant as an optimization.
|
||||
const glm::vec3 ENTITY_ITEM_ZERO_VEC3(0.0f);
|
||||
const glm::vec3 ENTITY_ITEM_ZERO_VEC3 = glm::vec3(0.0f);
|
||||
const glm::vec3 ENTITY_ITEM_ONE_VEC3 = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
const glm::vec3 ENTITY_ITEM_HALF_VEC3 = ENTITY_ITEM_ONE_VEC3 / 2.0f;
|
||||
|
||||
const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
|
||||
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
|
||||
|
@ -31,11 +33,12 @@ const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
|
|||
|
||||
const QString ENTITY_ITEM_DEFAULT_SCRIPT = QString("");
|
||||
const QString ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL = QString("");
|
||||
const glm::vec3 ENTITY_ITEM_DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f, 0.5f, 0.5f); // center
|
||||
const glm::vec3 ENTITY_ITEM_DEFAULT_REGISTRATION_POINT = ENTITY_ITEM_HALF_VEC3; // center
|
||||
|
||||
const float ENTITY_ITEM_IMMORTAL_LIFETIME = -1.0f; /// special lifetime which means the entity lives for ever
|
||||
const float ENTITY_ITEM_DEFAULT_LIFETIME = ENTITY_ITEM_IMMORTAL_LIFETIME;
|
||||
|
||||
const glm::vec3 ENTITY_ITEM_DEFAULT_POSITION = ENTITY_ITEM_ZERO_VEC3;
|
||||
const glm::quat ENTITY_ITEM_DEFAULT_ROTATION;
|
||||
const float ENTITY_ITEM_DEFAULT_WIDTH = 0.1f;
|
||||
const glm::vec3 ENTITY_ITEM_DEFAULT_DIMENSIONS = glm::vec3(ENTITY_ITEM_DEFAULT_WIDTH);
|
||||
|
|
|
@ -48,10 +48,10 @@ void LightEntityItem::setDimensions(const glm::vec3& value) {
|
|||
// recalculate the x/y dimensions to properly encapsulate the spotlight.
|
||||
const float length = value.z;
|
||||
const float width = length * glm::sin(glm::radians(_cutoff));
|
||||
_dimensions = glm::vec3(width, width, length);
|
||||
EntityItem::setDimensions(glm::vec3(width, width, length));
|
||||
} else {
|
||||
float maxDimension = glm::max(value.x, value.y, value.z);
|
||||
_dimensions = glm::vec3(maxDimension, maxDimension, maxDimension);
|
||||
EntityItem::setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,12 +73,12 @@ void LightEntityItem::setIsSpotlight(bool value) {
|
|||
_isSpotlight = value;
|
||||
|
||||
if (_isSpotlight) {
|
||||
const float length = _dimensions.z;
|
||||
const float length = getDimensions().z;
|
||||
const float width = length * glm::sin(glm::radians(_cutoff));
|
||||
_dimensions = glm::vec3(width, width, length);
|
||||
setDimensions(glm::vec3(width, width, length));
|
||||
} else {
|
||||
float maxDimension = glm::max(_dimensions.x, _dimensions.y, _dimensions.z);
|
||||
_dimensions = glm::vec3(maxDimension, maxDimension, maxDimension);
|
||||
float maxDimension = glm::max(getDimensions().x, getDimensions().y, getDimensions().z);
|
||||
setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,9 +89,9 @@ void LightEntityItem::setCutoff(float value) {
|
|||
if (_isSpotlight) {
|
||||
// If we are a spotlight, adjusting the cutoff will affect the area we encapsulate,
|
||||
// so update the dimensions to reflect this.
|
||||
const float length = _dimensions.z;
|
||||
const float length = getDimensions().z;
|
||||
const float width = length * glm::sin(glm::radians(_cutoff));
|
||||
_dimensions = glm::vec3(width, width, length);
|
||||
setDimensions(glm::vec3(width, width, length));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
|
||||
void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
|
||||
QVector<glm::vec3> sanitizedPoints;
|
||||
int invalidPoints = 0;
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
glm::vec3 point = points.at(i);
|
||||
// Make sure all of our points are valid numbers.
|
||||
|
@ -93,9 +94,12 @@ void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
|
|||
if (point.x > 0 && point.y > 0 && point.z > 0){
|
||||
sanitizedPoints << point;
|
||||
} else {
|
||||
qDebug() << "INVALID POINT";
|
||||
++invalidPoints;
|
||||
}
|
||||
}
|
||||
if (invalidPoints > 0) {
|
||||
qDebug() << "Line with" << invalidPoints << "INVALID POINTS";
|
||||
}
|
||||
_points = sanitizedPoints;
|
||||
_pointsChanged = true;
|
||||
}
|
||||
|
@ -144,8 +148,8 @@ void LineEntityItem::debugDump() const {
|
|||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << " LINE EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
|
||||
qCDebug(entities) << " position:" << debugTreeVector(_position);
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions);
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
}
|
||||
|
||||
|
|
|
@ -276,8 +276,8 @@ void ParticleEffectEntityItem::debugDump() const {
|
|||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << "PA EFFECT EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2];
|
||||
qCDebug(entities) << " position:" << debugTreeVector(_position);
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions);
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
}
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeB
|
|||
void PolyVoxEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << " POLYVOX EntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " position:" << debugTreeVector(_position);
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions);
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions());
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue