3
0
Fork 0
mirror of https://github.com/JulianGro/overte.git synced 2025-04-30 02:03:18 +02:00

Merge branch 'team-teaching' of https://github.com/highfidelity/hifi into text-renderer

This commit is contained in:
Atlante45 2015-05-28 16:13:24 +02:00
commit bca80addef
110 changed files with 2302 additions and 1362 deletions
CMakeLists.txt
domain-server/resources/web/settings/js
examples
interface/src
libraries
avatars/src
entities-renderer
entities/src
networking/src
physics/src
render-utils/src
render/src/render

View file

@ -40,7 +40,8 @@ if (WIN32)
endif ()
message (WINDOW_SDK_PATH= ${WINDOW_SDK_PATH})
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${WINDOW_SDK_PATH})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
# /wd4351 disables warning C4351: new behavior: elements of array will be default initialized
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4351")
# /LARGEADDRESSAWARE enables 32-bit apps to use more than 2GB of memory.
# Caveats: http://stackoverflow.com/questions/2288728/drawbacks-of-using-largeaddressaware-for-32-bit-windows-executables
# TODO: Remove when building 64-bit.

View file

@ -262,7 +262,6 @@ $(document).ready(function(){
$('#' + Settings.FORM_ID).on('click', '#' + Settings.CONNECT_ACCOUNT_BTN_ID, function(e){
$(this).blur();
prepareAccessTokenPrompt();
e.preventDefault();
});
var panelsSource = $('#panels-template').html()

0
examples/blockWorld.js Normal file
View file

View file

@ -153,6 +153,26 @@ if (showScore) {
var BULLET_VELOCITY = 10.0;
function entityCollisionWithEntity(entity1, entity2, collision) {
if (entity2 === targetID) {
score++;
if (showScore) {
Overlays.editOverlay(text, { text: "Score: " + score } );
}
// We will delete the bullet and target in 1/2 sec, but for now we can see them bounce!
Script.setTimeout(deleteBulletAndTarget, 500);
// Turn the target and the bullet white
Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }});
Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }});
// play the sound near the camera so the shooter can hear it
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
Audio.playSound(targetHitSound, audioOptions);
}
}
function shootBullet(position, velocity, grenade) {
var BULLET_SIZE = 0.10;
var BULLET_LIFETIME = 10.0;
@ -178,6 +198,7 @@ function shootBullet(position, velocity, grenade) {
ignoreCollisions: false,
collisionsWillMove: true
});
Script.addEventHandler(bulletID, "collisionWithEntity", entityCollisionWithEntity);
// Play firing sounds
audioOptions.position = position;
@ -310,27 +331,6 @@ function makePlatform(gravity, scale, size) {
}
function entityCollisionWithEntity(entity1, entity2, collision) {
if (((entity1.id == bulletID.id) || (entity1.id == targetID.id)) &&
((entity2.id == bulletID.id) || (entity2.id == targetID.id))) {
score++;
if (showScore) {
Overlays.editOverlay(text, { text: "Score: " + score } );
}
// We will delete the bullet and target in 1/2 sec, but for now we can see them bounce!
Script.setTimeout(deleteBulletAndTarget, 500);
// Turn the target and the bullet white
Entities.editEntity(entity1, { color: { red: 255, green: 255, blue: 255 }});
Entities.editEntity(entity2, { color: { red: 255, green: 255, blue: 255 }});
// play the sound near the camera so the shooter can hear it
audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
Audio.playSound(targetHitSound, audioOptions);
}
}
function keyPressEvent(event) {
// if our tools are off, then don't do anything
if (event.text == "t") {
@ -505,7 +505,6 @@ function scriptEnding() {
clearPose();
}
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
Script.scriptEnding.connect(scriptEnding);
Script.update.connect(update);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);

View file

@ -0,0 +1,53 @@
//
// entityCollisionExample.js
// examples
//
// Created by Howard Stearns on 5/25/15.
// Copyright 2015 High Fidelity, Inc.
//
// This is an example script that demonstrates use of the per-entity event handlers.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
function someCollisionFunction(entityA, entityB, collision) {
print("collision: " + JSON.stringify({a: entityA, b: entityB, c: collision}));
}
var position = Vec3.sum(MyAvatar.position, Quat.getFront(MyAvatar.orientation));
var properties = {
type: "Box",
position: position,
collisionsWillMove: true,
color: { red: 200, green: 0, blue: 0 }
};
var collider = Entities.addEntity(properties);
var armed = false;
function togglePrinting() {
print('togglePrinting from ' + armed + ' on ' + collider);
if (armed) {
Script.removeEventHandler(collider, "collisionWithEntity", someCollisionFunction);
} else {
Script.addEventHandler(collider, "collisionWithEntity", someCollisionFunction);
}
armed = !armed;
print("Red box " + (armed ? "will" : "will not") + " print on collision.");
}
togglePrinting();
properties.position.y += 0.2;
properties.color.blue += 200;
// A handy target for the collider to hit.
var target = Entities.addEntity(properties);
properties.position.y += 0.2;
properties.color.green += 200;
var button = Entities.addEntity(properties);
Script.addEventHandler(button, "clickReleaseOnEntity", togglePrinting);
Script.scriptEnding.connect(function () {
Entities.deleteEntity(collider);
Entities.deleteEntity(target);
Entities.deleteEntity(button);
});

View file

@ -33,8 +33,8 @@ var cuePosition;
var startStroke = 0;
// Sounds to use
hitSounds = [];
hitSounds.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "Collisions-ballhitsandcatches/billiards/collision1.wav"));
var hitSound = HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav";
SoundCache.getSound(hitSound);
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var screenSize = Controller.getViewportDimensions();
@ -127,6 +127,7 @@ function makeBalls(pos) {
ignoreCollisions: false,
damping: 0.50,
shapeType: "sphere",
collisionSoundURL: hitSound,
collisionsWillMove: true }));
ballPosition.z += (BALL_SIZE + BALL_GAP) * SCALE;
ballNumber++;
@ -225,26 +226,11 @@ function update(deltaTime) {
}
}
function entityCollisionWithEntity(entity1, entity2, collision) {
/*
NOT WORKING YET
if ((entity1.id == cueBall.id) || (entity2.id == cueBall.id)) {
print("Cue ball collision!");
//audioOptions.position = Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation()));
//Audio.playSound(hitSounds[0], { position: Vec3.sum(Camera.getPosition(), Quat.getFront(Camera.getOrientation())) });
}
else if (isObjectBall(entity1.id) || isObjectBall(entity2.id)) {
print("Object ball collision");
} */
}
tableCenter = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation())));
makeTable(tableCenter);
makeBalls(tableCenter);
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
Script.scriptEnding.connect(cleanup);
Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent);

View file

@ -21,6 +21,16 @@ var gameOver = false;
var invaderStepsPerCycle = 120; // the number of update steps it takes then invaders to move one column to the right
var invaderStepOfCycle = 0; // current iteration in the cycle
var invaderMoveDirection = 1; // 1 for moving to right, -1 for moving to left
var LEFT = ",";
var RIGHT = ".";
var FIRE = "SPACE";
var QUIT = "q";
print("Use:");
print(LEFT + " to move left");
print(RIGHT + " to move right");
print(FIRE + " to fire");
print(QUIT + " to quit");
// game length...
var itemLifetimes = 60; // 1 minute
@ -65,8 +75,8 @@ var myShipProperties;
// create the rows of space invaders
var invaders = new Array();
var numberOfRows = 5;
var invadersPerRow = 8;
var numberOfRows = 3 // FIXME 5;
var invadersPerRow = 3 // FIXME 8;
var emptyColumns = 2; // number of invader width columns not filled with invaders
var invadersBottomCorner = { x: gameAt.x, y: middleY , z: gameAt.z };
var rowHeight = ((gameAt.y + gameSize.y) - invadersBottomCorner.y) / numberOfRows;
@ -80,7 +90,6 @@ var stepsToGround = (middleY - gameAt.y) / yPerStep;
var maxInvaderRowOffset=stepsToGround;
// missile related items
var missileFired = false;
var myMissile;
// sounds
@ -174,6 +183,7 @@ function initializeInvaders() {
invaderPosition = getInvaderPosition(row, column);
invaders[row][column] = Entities.addEntity({
type: "Model",
shapeType: "box",
position: invaderPosition,
velocity: { x: 0, y: 0, z: 0 },
gravity: { x: 0, y: 0, z: 0 },
@ -181,6 +191,7 @@ function initializeInvaders() {
dimensions: { x: invaderSize * 2, y: invaderSize * 2, z: invaderSize * 2 },
color: { red: 255, green: 0, blue: 0 },
modelURL: invaderModels[row].modelURL,
collisionsWillMove: true,
lifetime: itemLifetimes
});
}
@ -264,17 +275,17 @@ Script.update.connect(update);
function cleanupGame() {
print("cleaning up game...");
Entities.deleteEntity(myShip);
print("cleanupGame() ... Entities.deleteEntity(myShip)... myShip.id="+myShip.id);
print("cleanupGame() ... Entities.deleteEntity(myShip)... myShip="+myShip);
for (var row = 0; row < numberOfRows; row++) {
for (var column = 0; column < invadersPerRow; column++) {
Entities.deleteEntity(invaders[row][column]);
print("cleanupGame() ... Entities.deleteEntity(invaders[row][column])... invaders[row][column].id="
+invaders[row][column].id);
print("cleanupGame() ... Entities.deleteEntity(invaders[row][column])... invaders[row][column]="
+invaders[row][column]);
}
}
// clean up our missile
if (missileFired) {
if (myMissile) {
Entities.deleteEntity(myMissile);
}
@ -293,15 +304,23 @@ function moveShipTo(position) {
Entities.editEntity(myShip, { position: position });
}
function entityCollisionWithEntity(entityA, entityB, collision) {
print("entityCollisionWithEntity() a="+entityA + " b=" + entityB);
Vec3.print('entityCollisionWithEntity() penetration=', collision.penetration);
Vec3.print('entityCollisionWithEntity() contactPoint=', collision.contactPoint);
deleteIfInvader(entityB);
}
function fireMissile() {
// we only allow one missile at a time...
var canFire = false;
// If we've fired a missile, then check to see if it's still alive
if (missileFired) {
if (myMissile) {
var missileProperties = Entities.getEntityProperties(myMissile);
if (!missileProperties) {
if (!missileProperties || (missileProperties.type === 'Unknown')) {
print("canFire = true");
canFire = true;
}
@ -322,11 +341,12 @@ function fireMissile() {
velocity: { x: 0, y: 5, z: 0},
gravity: { x: 0, y: 0, z: 0 },
damping: 0,
dimensions: { x: missileSize * 2, y: missileSize * 2, z: missileSize * 2 },
collisionsWillMove: true,
dimensions: { x: missileSize, y: missileSize, z: missileSize },
color: { red: 0, green: 0, blue: 255 },
lifetime: 5
});
Script.addEventHandler(myMissile, "collisionWithEntity", entityCollisionWithEntity);
var options = {}
if (soundInMyHead) {
options.position = { x: MyAvatar.position.x + 0.0,
@ -335,30 +355,30 @@ function fireMissile() {
} else {
options.position = missilePosition;
}
Audio.playSound(shootSound, options);
missileFired = true;
}
}
function keyPressEvent(key) {
//print("keyPressEvent key.text="+key.text);
if (key.text == ",") {
if (key.text == LEFT) {
myShipProperties.position.x -= 0.1;
if (myShipProperties.position.x < gameAt.x) {
myShipProperties.position.x = gameAt.x;
}
moveShipTo(myShipProperties.position);
} else if (key.text == ".") {
} else if (key.text == RIGHT) {
myShipProperties.position.x += 0.1;
if (myShipProperties.position.x > gameAt.x + gameSize.x) {
myShipProperties.position.x = gameAt.x + gameSize.x;
}
moveShipTo(myShipProperties.position);
} else if (key.text == "f") {
} else if (key.text == FIRE) {
fireMissile();
} else if (key.text == "q") {
} else if (key.text == QUIT) {
endGame();
}
}
@ -370,7 +390,7 @@ Controller.captureKeyEvents({text: " "});
function deleteIfInvader(possibleInvaderEntity) {
for (var row = 0; row < numberOfRows; row++) {
for (var column = 0; column < invadersPerRow; column++) {
if (invaders[row][column].id && invaders[row][column].id == possibleInvaderEntity.id) {
if (invaders[row][column] == possibleInvaderEntity) {
Entities.deleteEntity(possibleInvaderEntity);
Entities.deleteEntity(myMissile);
@ -390,20 +410,6 @@ function deleteIfInvader(possibleInvaderEntity) {
}
}
function entityCollisionWithEntity(entityA, entityB, collision) {
print("entityCollisionWithEntity() a.id="+entityA.id + " b.id=" + entityB.id);
Vec3.print('entityCollisionWithEntity() penetration=', collision.penetration);
Vec3.print('entityCollisionWithEntity() contactPoint=', collision.contactPoint);
if (missileFired) {
if (myMissile.id == entityA.id) {
deleteIfInvader(entityB);
} else if (myMissile.id == entityB.id) {
deleteIfInvader(entityA);
}
}
}
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
// initialize the game...
initializeMyShip();

View file

@ -12,17 +12,6 @@
//
print("hello...");
function entityCollisionWithEntity(entityA, entityB, collision) {
print("entityCollisionWithParticle()..");
print(" entityA.getID()=" + entityA.id);
print(" entityB.getID()=" + entityB.id);
Vec3.print('penetration=', collision.penetration);
Vec3.print('contactPoint=', collision.contactPoint);
}
Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity);
print("here... hello...");
print("The global collision event is obsolete. Please instead use:");
print(" the collisionSoundURL property on entities, or");
print(" entityCollisionExample.js");

View file

@ -1,9 +1,88 @@
// pointer.js
// examples
//
// Created by Eric Levin on May 26, 2015
// Copyright 2015 High Fidelity, Inc.
//
// Provides a pointer with option to draw on surfaces
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var lineEntityID = null;
var lineIsRezzed = false;
var altHeld = false;
var lineCreated = false;
var position, positionOffset, prevPosition;
var nearLinePosition;
var strokes = [];
var STROKE_ADJUST = 0.005;
var DISTANCE_DRAW_THRESHOLD = .02;
var drawDistance = 0;
function nearLinePoint(targetPosition) {
var LINE_WIDTH = 20;
var userCanPoint = false;
var userCanDraw = false;
var BUTTON_SIZE = 32;
var PADDING = 3;
var buttonOffColor = {
red: 250,
green: 10,
blue: 10
};
var buttonOnColor = {
red: 10,
green: 200,
blue: 100
};
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var screenSize = Controller.getViewportDimensions();
var drawButton = Overlays.addOverlay("image", {
x: screenSize.x / 2 - BUTTON_SIZE + PADDING * 2,
y: screenSize.y - (BUTTON_SIZE + PADDING),
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: HIFI_PUBLIC_BUCKET + "images/pencil.png?v2",
color: buttonOffColor,
alpha: 1
});
var pointerButton = Overlays.addOverlay("image", {
x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
y: screenSize.y - (BUTTON_SIZE + PADDING),
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png",
color: buttonOffColor,
alpha: 1
})
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2.0, Quat.getFront(Camera.getOrientation())));
center.y += 0.5;
var whiteBoard = Entities.addEntity({
type: "Box",
position: center,
dimensions: {
x: 1,
y: 1,
z: .001
},
color: {
red: 255,
green: 255,
blue: 255
}
});
function calculateNearLinePosition(targetPosition) {
var handPosition = MyAvatar.getRightPalmPosition();
var along = Vec3.subtract(targetPosition, handPosition);
along = Vec3.normalize(along);
@ -22,30 +101,39 @@ function removeLine() {
function createOrUpdateLine(event) {
if (!userCanPoint) {
return;
}
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
var props = Entities.getEntityProperties(intersection.entityID);
if (intersection.intersects) {
var dim = Vec3.subtract(intersection.intersection, nearLinePoint(intersection.intersection));
startPosition = intersection.intersection;
var subtractVec = Vec3.multiply(Vec3.normalize(pickRay.direction), STROKE_ADJUST);
startPosition = Vec3.subtract(startPosition, subtractVec);
nearLinePosition = calculateNearLinePosition(intersection.intersection);
positionOffset = Vec3.subtract(startPosition, nearLinePosition);
if (lineIsRezzed) {
Entities.editEntity(lineEntityID, {
position: nearLinePoint(intersection.intersection),
dimensions: dim,
lifetime: 15 + props.lifespan // renew lifetime
position: nearLinePosition,
dimensions: positionOffset,
});
if (userCanDraw) {
draw();
}
} else {
lineIsRezzed = true;
prevPosition = startPosition;
lineEntityID = Entities.addEntity({
type: "Line",
position: nearLinePoint(intersection.intersection),
dimensions: dim,
position: nearLinePosition,
dimensions: positionOffset,
color: {
red: 255,
green: 255,
blue: 255
},
lifetime: 15 // if someone crashes while pointing, don't leave the line there forever.
});
}
} else {
@ -53,8 +141,69 @@ function createOrUpdateLine(event) {
}
}
function draw() {
//We only want to draw line if distance between starting and previous point is large enough
drawDistance = Vec3.distance(startPosition, prevPosition);
if (drawDistance < DISTANCE_DRAW_THRESHOLD) {
return;
}
var offset = Vec3.subtract(startPosition, prevPosition);
strokes.push(Entities.addEntity({
type: "Line",
position: prevPosition,
dimensions: offset,
color: {
red: 200,
green: 40,
blue: 200
},
lineWidth: LINE_WIDTH
}));
prevPosition = startPosition;
}
function mousePressEvent(event) {
var clickedOverlay = Overlays.getOverlayAtPoint({
x: event.x,
y: event.y
});
if (clickedOverlay == drawButton) {
userCanDraw = !userCanDraw;
if (userCanDraw === true) {
Overlays.editOverlay(drawButton, {
color: buttonOnColor
});
} else {
Overlays.editOverlay(drawButton, {
color: buttonOffColor
});
}
}
if (clickedOverlay == pointerButton) {
userCanPoint = !userCanPoint;
if (userCanPoint === true) {
Overlays.editOverlay(pointerButton, {
color: buttonOnColor
});
if (userCanDraw === true) {
Overlays.editOverlay(drawButton, {
color: buttonOnColor
});
}
} else {
Overlays.editOverlay(pointerButton, {
color: buttonOffColor
});
Overlays.editOverlay(drawButton, {
color: buttonOffColor
});
}
}
if (!event.isLeftButton || altHeld) {
return;
}
@ -64,11 +213,13 @@ function mousePressEvent(event) {
}
function mouseMoveEvent(event) {
createOrUpdateLine(event);
}
function mouseReleaseEvent(event) {
if (!lineCreated) {
return;
@ -91,7 +242,18 @@ function keyReleaseEvent(event) {
}
function cleanup() {
Entities.deleteEntity(whiteBoard);
for (var i = 0; i < strokes.length; i++) {
Entities.deleteEntity(strokes[i]);
}
Overlays.deleteOverlay(drawButton);
Overlays.deleteOverlay(pointerButton);
}
Script.scriptEnding.connect(cleanup);
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);

View file

@ -370,7 +370,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_bookmarks = new Bookmarks(); // Before setting up the menu
_runningScriptsWidget = new RunningScriptsWidget(_window);
_renderEngine->buildStandardTaskPipeline();
_renderEngine->registerScene(_main3DScene);
// start the nodeThread so its event loop is running
QThread* nodeThread = new QThread(this);
nodeThread->setObjectName("Datagram Processor Thread");
@ -1986,7 +1990,7 @@ void Application::toggleFaceTrackerMute() {
}
bool Application::exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs) {
QVector<EntityItem*> entities;
QVector<EntityItemPointer> entities;
auto entityTree = _entities.getTree();
EntityTree exportTree;
@ -2027,7 +2031,7 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
}
bool Application::exportEntities(const QString& filename, float x, float y, float z, float scale) {
QVector<EntityItem*> entities;
QVector<EntityItemPointer> entities;
_entities.getTree()->findEntities(AACube(glm::vec3(x, y, z), scale), entities);
if (entities.size() > 0) {
@ -2171,9 +2175,6 @@ void Application::init() {
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(&_entitySimulation, &EntitySimulation::entityCollisionWithEntity,
entityScriptingInterface.data(), &EntityScriptingInterface::entityCollisionWithEntity);
// connect the _entityCollisionSystem to our EntityTreeRenderer since that's what handles running entity scripts
connect(&_entitySimulation, &EntitySimulation::entityCollisionWithEntity,
&_entities, &EntityTreeRenderer::entityCollisionWithEntity);
@ -2283,8 +2284,8 @@ void Application::updateMyAvatarLookAtPosition() {
}
} else {
AvatarSharedPointer lookingAt = _myAvatar->getLookAtTargetAvatar().toStrongRef();
if (lookingAt && _myAvatar != lookingAt.data()) {
AvatarSharedPointer lookingAt = _myAvatar->getLookAtTargetAvatar().lock();
if (lookingAt && _myAvatar != lookingAt.get()) {
isLookingAtSomeone = true;
// If I am looking at someone else, look directly at one of their eyes
@ -2292,17 +2293,17 @@ void Application::updateMyAvatarLookAtPosition() {
// If a face tracker is active, look at the eye for the side my gaze is biased toward
if (tracker->getEstimatedEyeYaw() > _myAvatar->getHead()->getFinalYaw()) {
// Look at their right eye
lookAtSpot = static_cast<Avatar*>(lookingAt.data())->getHead()->getRightEyePosition();
lookAtSpot = static_cast<Avatar*>(lookingAt.get())->getHead()->getRightEyePosition();
} else {
// Look at their left eye
lookAtSpot = static_cast<Avatar*>(lookingAt.data())->getHead()->getLeftEyePosition();
lookAtSpot = static_cast<Avatar*>(lookingAt.get())->getHead()->getLeftEyePosition();
}
} else {
// Need to add randomly looking back and forth between left and right eye for case with no tracker
if (_myAvatar->isLookingAtLeftEye()) {
lookAtSpot = static_cast<Avatar*>(lookingAt.data())->getHead()->getLeftEyePosition();
lookAtSpot = static_cast<Avatar*>(lookingAt.get())->getHead()->getLeftEyePosition();
} else {
lookAtSpot = static_cast<Avatar*>(lookingAt.data())->getHead()->getRightEyePosition();
lookAtSpot = static_cast<Avatar*>(lookingAt.get())->getHead()->getRightEyePosition();
}
}
} else {
@ -3023,11 +3024,6 @@ void Application::updateShadowMap(RenderArgs* renderArgs) {
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
{
PerformanceTimer perfTimer("avatarManager");
DependencyManager::get<AvatarManager>()->renderAvatars(renderArgs);
}
{
PerformanceTimer perfTimer("entities");
_entities.render(renderArgs);
@ -3170,6 +3166,36 @@ const ViewFrustum* Application::getDisplayViewFrustum() const {
return &_displayViewFrustum;
}
// WorldBox Render Data & rendering functions
class WorldBoxRenderData {
public:
typedef render::Payload<WorldBoxRenderData> Payload;
typedef Payload::DataPointer Pointer;
static render::ItemID _item; // unique WorldBoxRenderData
};
render::ItemID WorldBoxRenderData::_item = 0;
namespace render {
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
if (args->_renderMode != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
PerformanceTimer perfTimer("worldBox");
renderWorldBox();
}
// never the less
float originSphereRadius = 0.05f;
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
}
}
void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly) {
activeRenderingThread = QThread::currentThread();
PROFILE_RANGE(__FUNCTION__);
@ -3332,11 +3358,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
DependencyManager::get<DeferredLightingEffect>()->prepare();
if (!selfAvatarOnly) {
// draw a red sphere
float originSphereRadius = 0.05f;
DependencyManager::get<GeometryCache>()->renderSphere(originSphereRadius, 15, 15, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
// render JS/scriptable overlays
{
PerformanceTimer perfTimer("3dOverlays");
@ -3380,16 +3402,32 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
DependencyManager::get<AmbientOcclusionEffect>()->render();
}
}
bool mirrorMode = (theCamera.getMode() == CAMERA_MODE_MIRROR);
{
PerformanceTimer perfTimer("avatars");
renderArgs->_renderMode = mirrorMode ? RenderArgs::MIRROR_RENDER_MODE : RenderArgs::NORMAL_RENDER_MODE;
DependencyManager::get<AvatarManager>()->renderAvatars(renderArgs, false, selfAvatarOnly);
renderArgs->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
render::Scene::PendingChanges pendingChanges;
// Make sure the WorldBox is in the scene
if (WorldBoxRenderData::_item == 0) {
auto worldBoxRenderData = WorldBoxRenderData::Pointer(new WorldBoxRenderData());
auto worldBoxRenderPayload = render::PayloadPointer(new WorldBoxRenderData::Payload(worldBoxRenderData));
WorldBoxRenderData::_item = _main3DScene->allocateID();
pendingChanges.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
}
_main3DScene->enqueuePendingChanges(pendingChanges);
_main3DScene->processPendingChangesQueue();
// FOr now every frame pass the renderCOntext
render::RenderContext renderContext;
renderContext.args = renderArgs;
_renderEngine->setRenderContext(renderContext);
// Before the deferred pass, let's try to use the render engine
_renderEngine->run();
{
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
@ -3401,13 +3439,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
PerformanceTimer perfTimer("lighting");
DependencyManager::get<DeferredLightingEffect>()->render();
}
{
PerformanceTimer perfTimer("avatarsPostLighting");
renderArgs->_renderMode = mirrorMode ? RenderArgs::MIRROR_RENDER_MODE : RenderArgs::NORMAL_RENDER_MODE;
DependencyManager::get<AvatarManager>()->renderAvatars(renderArgs, true, selfAvatarOnly);
renderArgs->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
}
//Render the sixense lasers
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
@ -3416,12 +3447,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
if (!selfAvatarOnly) {
_nodeBoundsDisplay.draw();
// Render the world box
if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
PerformanceTimer perfTimer("worldBox");
renderWorldBox();
}
// render octree fades if they exist
if (_octreeFades.size() > 0) {

View file

@ -77,6 +77,7 @@
#include "octree/OctreePacketProcessor.h"
#include "UndoStackScriptingInterface.h"
#include "render/Engine.h"
class QGLWidget;
class QKeyEvent;
@ -347,6 +348,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:
@ -670,6 +676,9 @@ private:
int _maxOctreePPS = DEFAULT_MAX_OCTREE_PPS;
quint64 _lastFaceTrackerUpdate;
render::ScenePointer _main3DScene{ new render::Scene() };
render::EnginePointer _renderEngine{ new render::Engine() };
};
#endif // hifi_Application_h

View file

@ -60,6 +60,25 @@ 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());
args->_elementsTouched++;
}
}
}
Avatar::Avatar() :
AvatarData(),
_skeletonModel(this),
@ -116,6 +135,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;

View file

@ -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,6 +74,10 @@ public:
Avatar();
~Avatar();
typedef render::Payload<AvatarData> Payload;
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
typedef Payload::DataPointer Pointer;
void init();
void simulate(float deltaTime);
@ -87,6 +99,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;
@ -220,9 +234,10 @@ protected:
virtual void renderAttachments(RenderArgs* args);
virtual void updateJointMappings();
render::ItemID _renderItemID;
private:
bool _initialized;
NetworkTexturePointer _billboardTexture;
bool _shouldRenderBillboard;

View file

@ -55,12 +55,22 @@ 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();
auto avatarPayload = new render::Payload<AvatarData>(_myAvatar);
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
static_cast<Avatar*>(_myAvatar.get())->_renderItemID = scene->allocateID();
render::Scene::PendingChanges pendingChanges;
pendingChanges.resetItem(static_cast<Avatar*>(_myAvatar.get())->_renderItemID, avatarPayloadPointer);
scene->enqueuePendingChanges(pendingChanges);
}
void AvatarManager::updateMyAvatar(float deltaTime) {
@ -92,9 +102,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 +121,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
simulateAvatarFades(deltaTime);
}
void AvatarManager::renderAvatars(RenderArgs* renderArgs, 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(renderArgs, cameraPosition, postLighting);
avatar->setDisplayingLookatVectors(renderLookAtVectors);
}
renderAvatarFades(renderArgs, cameraPosition);
}
} else {
// just render myAvatar
_myAvatar->render(renderArgs, cameraPosition, postLighting);
_myAvatar->setDisplayingLookatVectors(renderLookAtVectors);
}
}
void AvatarManager::simulateAvatarFades(float deltaTime) {
QVector<AvatarSharedPointer>::iterator fadingIterator = _avatarFades.begin();
@ -144,7 +128,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,18 +139,6 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
}
}
void AvatarManager::renderAvatarFades(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
// render avatar fades
Glower glower(renderArgs, renderArgs->_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(renderArgs, cameraPosition);
}
}
}
AvatarSharedPointer AvatarManager::newSharedAvatar() {
return AvatarSharedPointer(new Avatar());
}
@ -174,6 +146,17 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() {
// virtual
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer);
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
auto avatarPayload = new render::Payload<AvatarData>(avatar);
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload);
static_cast<Avatar*>(avatar.get())->_renderItemID = scene->allocateID();
render::Scene::PendingChanges pendingChanges;
pendingChanges.resetItem(static_cast<Avatar*>(avatar.get())->_renderItemID, avatarPayloadPointer);
scene->enqueuePendingChanges(pendingChanges);
return avatar;
}
@ -194,13 +177,18 @@ 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());
if (avatar != _myAvatar && avatar->isInitialized()) {
Avatar* avatar = reinterpret_cast<Avatar*>(avatarIterator.value().get());
if (avatar != _myAvatar.get() && avatar->isInitialized()) {
removeAvatarMotionState(avatar);
_avatarFades.push_back(avatarIterator.value());
_avatarHash.erase(avatarIterator);
}
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
render::Scene::PendingChanges pendingChanges;
pendingChanges.removeItem(avatar->_renderItemID);
scene->enqueuePendingChanges(pendingChanges);
}
}
@ -208,8 +196,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 +264,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);

View file

@ -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* renderArgs, bool postLighting = false, bool selfAvatarOnly = false);
void clearOtherAvatars();
@ -70,7 +69,6 @@ private:
AvatarManager(const AvatarManager& other);
void simulateAvatarFades(float deltaTime);
void renderAvatarFades(RenderArgs* renderArgs, const glm::vec3& cameraPosition);
// 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;

View file

@ -30,7 +30,7 @@ ModelReferential::ModelReferential(Referential* referential, EntityTree* tree, A
return;
}
const EntityItem* item = _tree->findEntityByID(_entityID);
EntityItemPointer item = _tree->findEntityByID(_entityID);
if (item != NULL) {
_lastRefDimension = item->getDimensions();
_refRotation = item->getRotation();
@ -44,7 +44,7 @@ ModelReferential::ModelReferential(const QUuid& entityID, EntityTree* tree, Avat
_entityID(entityID),
_tree(tree)
{
const EntityItem* item = _tree->findEntityByID(_entityID);
EntityItemPointer item = _tree->findEntityByID(_entityID);
if (!isValid() || item == NULL) {
qCDebug(interfaceapp) << "ModelReferential::constructor(): Not Valid";
_isValid = false;
@ -61,7 +61,7 @@ ModelReferential::ModelReferential(const QUuid& entityID, EntityTree* tree, Avat
}
void ModelReferential::update() {
const EntityItem* item = _tree->findEntityByID(_entityID);
EntityItemPointer item = _tree->findEntityByID(_entityID);
if (!isValid() || item == NULL || _avatar == NULL) {
return;
}
@ -105,7 +105,7 @@ JointReferential::JointReferential(Referential* referential, EntityTree* tree, A
return;
}
const EntityItem* item = _tree->findEntityByID(_entityID);
EntityItemPointer item = _tree->findEntityByID(_entityID);
const Model* model = getModel(item);
if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) {
_lastRefDimension = item->getDimensions();
@ -120,7 +120,7 @@ JointReferential::JointReferential(uint32_t jointIndex, const QUuid& entityID, E
_jointIndex(jointIndex)
{
_type = JOINT;
const EntityItem* item = _tree->findEntityByID(_entityID);
EntityItemPointer item = _tree->findEntityByID(_entityID);
const Model* model = getModel(item);
if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) {
qCDebug(interfaceapp) << "JointReferential::constructor(): Not Valid";
@ -139,7 +139,7 @@ JointReferential::JointReferential(uint32_t jointIndex, const QUuid& entityID, E
}
void JointReferential::update() {
const EntityItem* item = _tree->findEntityByID(_entityID);
EntityItemPointer item = _tree->findEntityByID(_entityID);
const Model* model = getModel(item);
if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) {
return;
@ -163,7 +163,7 @@ void JointReferential::update() {
}
}
const Model* JointReferential::getModel(const EntityItem* item) {
const Model* JointReferential::getModel(EntityItemPointer item) {
EntityItemFBXService* fbxService = _tree->getFBXService();
if (item != NULL && fbxService != NULL) {
return fbxService->getModelForEntityItem(item);

View file

@ -38,7 +38,7 @@ public:
virtual void update();
protected:
const Model* getModel(const EntityItem* item);
const Model* getModel(EntityItemPointer item);
virtual int packExtraData(unsigned char* destinationBuffer) const;
virtual int unpackExtraData(const unsigned char* sourceBuffer, int size);

View file

@ -105,7 +105,7 @@ MyAvatar::MyAvatar() :
}
MyAvatar::~MyAvatar() {
_lookAtTargetAvatar.clear();
_lookAtTargetAvatar.reset();
}
QByteArray MyAvatar::toByteArray() {
@ -335,7 +335,7 @@ void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, b
}
Avatar::render(renderArgs, cameraPosition, postLighting);
// don't display IK constraints in shadow mode
if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && postLighting) {
_skeletonModel.renderIKConstraints();
@ -856,7 +856,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 +868,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 +896,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() {

View file

@ -37,9 +37,9 @@ public:
void simulate(float deltaTime);
void updateFromTrackers(float deltaTime);
void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting = false);
void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bool postLighting, float glowLevel = 0.0f);
bool shouldRenderHead(const RenderArgs* renderArgs, const glm::vec3& cameraPosition) const override;
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();
@ -226,7 +226,7 @@ private:
DynamicCharacterController _characterController;
QWeakPointer<AvatarData> _lookAtTargetAvatar;
AvatarWeakPointer _lookAtTargetAvatar;
glm::vec3 _targetAvatarPosition;
bool _shouldRender;
bool _billboardValid;

View file

@ -141,13 +141,6 @@ static const float STARTING_DDE_MESSAGE_TIME = 0.033f;
static const float DEFAULT_DDE_EYE_CLOSING_THRESHOLD = 0.8f;
static const int CALIBRATION_SAMPLES = 150;
#ifdef WIN32
// warning C4351: new behavior: elements of array 'DdeFaceTracker::_lastEyeBlinks' will be default initialized
// warning C4351: new behavior: elements of array 'DdeFaceTracker::_filteredEyeBlinks' will be default initialized
// warning C4351: new behavior: elements of array 'DdeFaceTracker::_lastEyeCoefficients' will be default initialized
#pragma warning(disable:4351)
#endif
DdeFaceTracker::DdeFaceTracker() :
DdeFaceTracker(QHostAddress::Any, DDE_SERVER_PORT, DDE_CONTROL_PORT)
{
@ -214,10 +207,6 @@ DdeFaceTracker::~DdeFaceTracker() {
}
}
#ifdef WIN32
#pragma warning(default:4351)
#endif
void DdeFaceTracker::init() {
FaceTracker::init();
setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::UseCamera) && !_isMuted);

View file

@ -11,8 +11,6 @@
#include <GlowEffect.h>
#include "../../Menu.h"
#include "ModelOverlay.h"
ModelOverlay::ModelOverlay()

View file

@ -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;

View file

@ -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

View file

@ -12,4 +12,4 @@ find_package(Bullet REQUIRED)
target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${BULLET_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
link_hifi_libraries(shared gpu script-engine render-utils)
link_hifi_libraries(shared gpu script-engine render render-utils)

View file

@ -29,8 +29,11 @@
#include <TextureCache.h>
#include <SoundCache.h>
#include "EntityTreeRenderer.h"
#include "RenderableEntityItem.h"
#include "RenderableBoxEntityItem.h"
#include "RenderableLightEntityItem.h"
#include "RenderableModelEntityItem.h"
@ -92,6 +95,10 @@ void EntityTreeRenderer::clear() {
}
OctreeRenderer::clear();
_entityScripts.clear();
// TODO/FIXME - this needs to be fixed... we need to clear all items out of the scene in this case.
qDebug() << "EntityTreeRenderer::clear() need to clear the scene... ";
}
void EntityTreeRenderer::init() {
@ -114,7 +121,6 @@ void EntityTreeRenderer::init() {
connect(entityTree, &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity);
connect(entityTree, &EntityTree::addingEntity, this, &EntityTreeRenderer::addingEntity);
connect(entityTree, &EntityTree::entityScriptChanging, this, &EntityTreeRenderer::entitySciptChanging);
connect(entityTree, &EntityTree::changingEntityID, this, &EntityTreeRenderer::changingEntityID);
}
void EntityTreeRenderer::shutdown() {
@ -139,7 +145,7 @@ void EntityTreeRenderer::errorInLoadingScript(const QUrl& url) {
}
QScriptValue EntityTreeRenderer::loadEntityScript(const EntityItemID& entityItemID, bool isPreload) {
EntityItem* entity = static_cast<EntityTree*>(_tree)->findEntityByEntityItemID(entityItemID);
EntityItemPointer entity = static_cast<EntityTree*>(_tree)->findEntityByEntityItemID(entityItemID);
return loadEntityScript(entity, isPreload);
}
@ -191,7 +197,7 @@ QString EntityTreeRenderer::loadScriptContents(const QString& scriptMaybeURLorTe
}
QScriptValue EntityTreeRenderer::loadEntityScript(EntityItem* entity, bool isPreload) {
QScriptValue EntityTreeRenderer::loadEntityScript(EntityItemPointer entity, bool isPreload) {
if (_shuttingDown) {
return QScriptValue(); // since we're shutting down, we don't load any more scripts
}
@ -325,7 +331,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
if (avatarPosition != _lastAvatarPosition) {
float radius = 1.0f; // for now, assume 1 meter radius
QVector<const EntityItem*> foundEntities;
QVector<EntityItemPointer> foundEntities;
QVector<EntityItemID> entitiesContainingAvatar;
// find the entities near us
@ -333,7 +339,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() {
static_cast<EntityTree*>(_tree)->findEntities(avatarPosition, radius, foundEntities);
// create a list of entities that actually contain the avatar's position
foreach(const EntityItem* entity, foundEntities) {
foreach(EntityItemPointer entity, foundEntities) {
if (entity->contains(avatarPosition)) {
entitiesContainingAvatar << entity->getEntityItemID();
}
@ -394,7 +400,7 @@ void EntityTreeRenderer::leaveAllEntities() {
}
}
void EntityTreeRenderer::applyZonePropertiesToScene(const ZoneEntityItem* zone) {
void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone) {
QSharedPointer<SceneScriptingInterface> scene = DependencyManager::get<SceneScriptingInterface>();
if (zone) {
if (!_hasPreviousZone) {
@ -475,6 +481,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(const ZoneEntityItem* zone)
}
void EntityTreeRenderer::render(RenderArgs* renderArgs) {
if (_tree && !_shuttingDown) {
Model::startScene(renderArgs->_renderSide);
@ -496,7 +503,7 @@ void EntityTreeRenderer::render(RenderArgs* renderArgs) {
_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, renderArgs);
@ -510,7 +517,9 @@ void EntityTreeRenderer::render(RenderArgs* renderArgs) {
glPushMatrix();
renderArgs->_context->enqueueBatch(batch);
glPopMatrix();
renderArgs->_batch = nullptr;
// stats...
_meshesConsidered = renderArgs->_meshesConsidered;
_meshesRendered = renderArgs->_meshesRendered;
@ -532,12 +541,12 @@ void EntityTreeRenderer::render(RenderArgs* renderArgs) {
deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup
}
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* entityItem) {
const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(EntityItemPointer entityItem) {
const FBXGeometry* result = NULL;
if (entityItem->getType() == EntityTypes::Model) {
const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
assert(modelEntityItem); // we need this!!!
Model* model = modelEntityItem->getModel(this);
if (model) {
@ -547,23 +556,23 @@ const FBXGeometry* EntityTreeRenderer::getGeometryForEntity(const EntityItem* en
return result;
}
const Model* EntityTreeRenderer::getModelForEntityItem(const EntityItem* entityItem) {
const Model* EntityTreeRenderer::getModelForEntityItem(EntityItemPointer entityItem) {
const Model* result = NULL;
if (entityItem->getType() == EntityTypes::Model) {
const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
result = modelEntityItem->getModel(this);
}
return result;
}
const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(const EntityItem* entityItem) {
const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemPointer entityItem) {
const FBXGeometry* result = NULL;
if (entityItem->getType() == EntityTypes::Model) {
const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
if (constModelEntityItem->hasCompoundShapeURL()) {
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
std::shared_ptr<RenderableModelEntityItem> modelEntityItem =
std::dynamic_pointer_cast<RenderableModelEntityItem>(entityItem);
if (modelEntityItem->hasCompoundShapeURL()) {
Model* model = modelEntityItem->getModel(this);
if (model) {
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = model->getCollisionGeometry();
@ -609,7 +618,7 @@ void EntityTreeRenderer::renderElementProxy(EntityTreeElement* entityTreeElement
}
}
void EntityTreeRenderer::renderProxies(const EntityItem* entity, RenderArgs* args) {
void EntityTreeRenderer::renderProxies(EntityItemPointer entity, RenderArgs* args) {
bool isShadowMode = args->_renderMode == RenderArgs::SHADOW_RENDER_MODE;
if (!isShadowMode && _displayModelBounds) {
PerformanceTimer perfTimer("renderProxies");
@ -656,7 +665,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
// we need to iterate the actual entityItems of the element
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
QList<EntityItem*>& entityItems = entityTreeElement->getEntities();
EntityItems& entityItems = entityTreeElement->getEntities();
uint16_t numberOfEntities = entityItems.size();
@ -668,7 +677,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
}
for (uint16_t i = 0; i < numberOfEntities; i++) {
EntityItem* entityItem = entityItems[i];
EntityItemPointer entityItem = entityItems[i];
if (entityItem->isVisible()) {
@ -678,51 +687,54 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
float entityVolumeEstimate = entityItem->getVolumeEstimate();
if (entityVolumeEstimate < _bestZoneVolume) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = dynamic_cast<const ZoneEntityItem*>(entityItem);
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entityItem);
} else if (entityVolumeEstimate == _bestZoneVolume) {
if (!_bestZone) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = dynamic_cast<const ZoneEntityItem*>(entityItem);
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entityItem);
} else {
// in the case of the volume being equal, we will use the
// EntityItemID to deterministically pick one entity over the other
if (entityItem->getEntityItemID() < _bestZone->getEntityItemID()) {
_bestZoneVolume = entityVolumeEstimate;
_bestZone = dynamic_cast<const ZoneEntityItem*>(entityItem);
_bestZone = std::dynamic_pointer_cast<ZoneEntityItem>(entityItem);
}
}
}
}
}
// hack for models. :(
if (entityItem->getType() == EntityTypes::Model) {
// render entityItem
AABox entityBox = entityItem->getAABox();
// 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());
// 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);
bool outOfView = args->_viewFrustum->boxInFrustum(entityBox) == ViewFrustum::OUTSIDE;
if (!outOfView) {
bool bigEnoughToRender = _viewState->shouldRenderMesh(entityBox.getLargestDimension(), distance);
if (bigEnoughToRender) {
renderProxies(entityItem, args);
if (bigEnoughToRender) {
renderProxies(entityItem, args);
Glower* glower = NULL;
if (entityItem->getGlowLevel() > 0.0f) {
glower = new Glower(args, entityItem->getGlowLevel());
}
entityItem->render(args);
args->_itemsRendered++;
if (glower) {
delete glower;
Glower* glower = NULL;
if (entityItem->getGlowLevel() > 0.0f) {
glower = new Glower(args, entityItem->getGlowLevel());
}
entityItem->render(args);
args->_itemsRendered++;
if (glower) {
delete glower;
}
} else {
args->_itemsTooSmall++;
}
} else {
args->_itemsTooSmall++;
args->_itemsOutOfView++;
}
} else {
args->_itemsOutOfView++;
}
}
}
@ -817,7 +829,7 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons
EntityTree* entityTree = static_cast<EntityTree*>(_tree);
OctreeElement* element;
EntityItem* intersectedEntity = NULL;
EntityItemPointer intersectedEntity = NULL;
result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
(void**)&intersectedEntity, lockType, &result.accurate,
precisionPicking);
@ -855,6 +867,7 @@ void EntityTreeRenderer::connectSignalsToSlots(EntityScriptingInterface* entityS
connect(this, &EntityTreeRenderer::enterEntity, entityScriptingInterface, &EntityScriptingInterface::enterEntity);
connect(this, &EntityTreeRenderer::leaveEntity, entityScriptingInterface, &EntityScriptingInterface::leaveEntity);
connect(this, &EntityTreeRenderer::collisionWithEntity, entityScriptingInterface, &EntityScriptingInterface::collisionWithEntity);
}
QScriptValueList EntityTreeRenderer::createMouseEventArgs(const EntityItemID& entityID, QMouseEvent* event, unsigned int deviceID) {
@ -1048,10 +1061,34 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
checkAndCallUnload(entityID);
}
_entityScripts.remove(entityID);
// here's where we remove the entity payload from the scene
render::Scene::PendingChanges pendingChanges;
if (_entityToSceneItems.contains(entityID)) {
render::ItemID renderItem = _entityToSceneItems[entityID];
pendingChanges.removeItem(renderItem);
_viewState->getMain3DScene()->enqueuePendingChanges(pendingChanges);
}
}
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
checkAndCallPreload(entityID);
// here's where we add the entity payload to the scene
render::Scene::PendingChanges pendingChanges;
render::ItemID renderItem = _viewState->getMain3DScene()->allocateID();
_entityToSceneItems[entityID] = renderItem;
EntityItemPointer entity = static_cast<EntityTree*>(_tree)->findEntityByID(entityID);
auto renderData = RenderableEntityItem::Pointer(new RenderableEntityItem(entity));
auto renderPayload = render::PayloadPointer(new RenderableEntityItem::Payload(renderData));
pendingChanges.resetItem(renderItem, renderPayload);
_viewState->getMain3DScene()->enqueuePendingChanges(pendingChanges);
_viewState->getMain3DScene()->processPendingChangesQueue();
}
void EntityTreeRenderer::entitySciptChanging(const EntityItemID& entityID) {
@ -1083,16 +1120,8 @@ void EntityTreeRenderer::checkAndCallUnload(const EntityItemID& entityID) {
}
void EntityTreeRenderer::changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID) {
if (_entityScripts.contains(oldEntityID)) {
EntityScriptDetails details = _entityScripts[oldEntityID];
_entityScripts.remove(oldEntityID);
_entityScripts[newEntityID] = details;
}
}
void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityTree* entityTree, const EntityItemID& id, const Collision& collision) {
EntityItem* entity = entityTree->findEntityByEntityItemID(id);
EntityItemPointer entity = entityTree->findEntityByEntityItemID(id);
if (!entity) {
return;
}
@ -1169,6 +1198,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
playEntityCollisionSound(myNodeID, entityTree, idB, collision);
// And now the entity scripts
emit collisionWithEntity(idA, idB, collision);
QScriptValue entityScriptA = loadEntityScript(idA);
if (entityScriptA.property("collisionWithEntity").isValid()) {
QScriptValueList args;
@ -1178,6 +1208,7 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
entityScriptA.property("collisionWithEntity").call(entityScriptA, args);
}
emit collisionWithEntity(idB, idA, collision);
QScriptValue entityScriptB = loadEntityScript(idB);
if (entityScriptB.property("collisionWithEntity").isValid()) {
QScriptValueList args;
@ -1187,4 +1218,3 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
entityScriptB.property("collisionWithEntity").call(entityScriptA, args);
}
}

View file

@ -19,6 +19,7 @@
#include <EntityScriptingInterface.h> // for RayToEntityIntersectionResult
#include <MouseEvent.h>
#include <OctreeRenderer.h>
#include <render/Scene.h>
#include <ScriptCache.h>
#include <AbstractAudioInterface.h>
@ -60,9 +61,9 @@ public:
virtual void init();
virtual void render(RenderArgs* renderArgs) override;
virtual const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem);
virtual const Model* getModelForEntityItem(const EntityItem* entityItem);
virtual const FBXGeometry* getCollisionGeometryForEntity(const EntityItem* entityItem);
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem);
virtual const Model* getModelForEntityItem(EntityItemPointer entityItem);
virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem);
/// clears the tree
virtual void clear();
@ -105,11 +106,11 @@ signals:
void enterEntity(const EntityItemID& entityItemID);
void leaveEntity(const EntityItemID& entityItemID);
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
public slots:
void addingEntity(const EntityItemID& entityID);
void deletingEntity(const EntityItemID& entityID);
void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID);
void entitySciptChanging(const EntityItemID& entityID);
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
@ -123,13 +124,13 @@ protected:
virtual Octree* createTree() { return new EntityTree(true); }
private:
void applyZonePropertiesToScene(const ZoneEntityItem* zone);
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
void renderElementProxy(EntityTreeElement* entityTreeElement, RenderArgs* args);
void checkAndCallPreload(const EntityItemID& entityID);
void checkAndCallUnload(const EntityItemID& entityID);
QList<Model*> _releasedModels;
void renderProxies(const EntityItem* entity, RenderArgs* args);
void renderProxies(EntityItemPointer entity, RenderArgs* args);
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
bool precisionPicking);
@ -146,7 +147,7 @@ private:
ScriptEngine* _entitiesScriptEngine;
ScriptEngine* _sandboxScriptEngine;
QScriptValue loadEntityScript(EntityItem* entity, bool isPreload = false);
QScriptValue loadEntityScript(EntityItemPointer entity, bool isPreload = false);
QScriptValue loadEntityScript(const EntityItemID& entityItemID, bool isPreload = false);
QScriptValue getPreviouslyLoadedEntityScript(const EntityItemID& entityItemID);
QString loadScriptContents(const QString& scriptMaybeURLorText, bool& isURL, bool& isPending, QUrl& url);
@ -172,7 +173,7 @@ private:
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
bool _hasPreviousZone = false;
const ZoneEntityItem* _bestZone;
std::shared_ptr<ZoneEntityItem> _bestZone;
float _bestZoneVolume;
glm::vec3 _previousKeyLightColor;
@ -186,6 +187,8 @@ private:
float _previousStageHour;
int _previousStageDay;
QHash<EntityItemID, render::ItemID> _entityToSceneItems;
};
#endif // hifi_EntityTreeRenderer_h

View file

@ -19,8 +19,8 @@
#include "RenderableBoxEntityItem.h"
EntityItem* RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableBoxEntityItem(entityID, properties);
EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableBoxEntityItem(entityID, properties));
}
void RenderableBoxEntityItem::render(RenderArgs* args) {

View file

@ -17,7 +17,7 @@
class RenderableBoxEntityItem : public BoxEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableBoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
BoxEntityItem(entityItemID, properties)

View file

@ -0,0 +1,38 @@
//
// 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 RenderableEntityItem::Pointer& payload) {
return ItemKey::Builder::opaqueShape();
}
template <> const Item::Bound payloadGetBound(const RenderableEntityItem::Pointer& payload) {
if (payload && payload->entity) {
return payload->entity->getAABox();
}
return render::Item::Bound();
}
template <> void payloadRender(const RenderableEntityItem::Pointer& payload, RenderArgs* args) {
if (args) {
args->_elementsTouched++;
if (payload && payload->entity) {
if (payload->entity->getType() != EntityTypes::Model) {
payload->entity->render(args);
}
}
}
}
}

View file

@ -0,0 +1,33 @@
//
// 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 RenderableEntityItem {
public:
RenderableEntityItem(EntityItemPointer entity) : entity(entity) { }
typedef render::Payload<RenderableEntityItem> Payload;
typedef Payload::DataPointer Pointer;
EntityItemPointer entity;
};
namespace render {
template <> const ItemKey payloadGetKey(const RenderableEntityItem::Pointer& payload);
template <> const Item::Bound payloadGetBound(const RenderableEntityItem::Pointer& payload);
template <> void payloadRender(const RenderableEntityItem::Pointer& payload, RenderArgs* args);
}
#endif // hifi_RenderableEntityItem_h

View file

@ -20,8 +20,8 @@
#include "RenderableLightEntityItem.h"
EntityItem* RenderableLightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableLightEntityItem(entityID, properties);
EntityItemPointer RenderableLightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableLightEntityItem(entityID, properties));
}
void RenderableLightEntityItem::render(RenderArgs* args) {

View file

@ -16,7 +16,7 @@
class RenderableLightEntityItem : public LightEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableLightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
LightEntityItem(entityItemID, properties)

View file

@ -19,8 +19,8 @@
#include "RenderableLineEntityItem.h"
EntityItem* RenderableLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableLineEntityItem(entityID, properties);
EntityItemPointer RenderableLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableLineEntityItem(entityID, properties));
}
void RenderableLineEntityItem::render(RenderArgs* args) {
@ -29,7 +29,6 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
glm::vec3 p1 = ENTITY_ITEM_ZERO_VEC3;
glm::vec3 p2 = getDimensions();
glm::vec4 lineColor(toGlm(getXColor()), getLocalRenderAlpha());
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
batch.setModelTransform(getTransformToCenter());

View file

@ -17,7 +17,7 @@
class RenderableLineEntityItem : public LineEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
LineEntityItem(entityItemID, properties) { }

View file

@ -23,8 +23,8 @@
#include "EntitiesRendererLogging.h"
#include "RenderableModelEntityItem.h"
EntityItem* RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableModelEntityItem(entityID, properties);
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableModelEntityItem(entityID, properties));
}
RenderableModelEntityItem::~RenderableModelEntityItem() {

View file

@ -23,7 +23,7 @@ class EntityTreeRenderer;
class RenderableModelEntityItem : public ModelEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ModelEntityItem(entityItemID, properties),

View file

@ -20,8 +20,8 @@
#include "RenderableParticleEffectEntityItem.h"
EntityItem* RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableParticleEffectEntityItem(entityID, properties);
EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableParticleEffectEntityItem(entityID, properties));
}
RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :

View file

@ -16,7 +16,7 @@
class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual void render(RenderArgs* args);

View file

@ -20,8 +20,8 @@
#include "RenderableSphereEntityItem.h"
EntityItem* RenderableSphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableSphereEntityItem(entityID, properties);
EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableSphereEntityItem(entityID, properties));
}
void RenderableSphereEntityItem::render(RenderArgs* args) {

View file

@ -16,7 +16,7 @@
class RenderableSphereEntityItem : public SphereEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableSphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
SphereEntityItem(entityItemID, properties)

View file

@ -20,8 +20,8 @@
#include "RenderableTextEntityItem.h"
#include "GLMHelpers.h"
EntityItem* RenderableTextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableTextEntityItem(entityID, properties);
EntityItemPointer RenderableTextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableTextEntityItem(entityID, properties));
}
void RenderableTextEntityItem::render(RenderArgs* args) {

View file

@ -19,7 +19,7 @@ const int FIXED_FONT_POINT_SIZE = 40;
class RenderableTextEntityItem : public TextEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableTextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
TextEntityItem(entityItemID, properties)

View file

@ -28,8 +28,8 @@
const float DPI = 30.47f;
const float METERS_TO_INCHES = 39.3701f;
EntityItem* RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableWebEntityItem(entityID, properties);
EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableWebEntityItem(entityID, properties));
}
RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :

View file

@ -17,7 +17,7 @@ class OffscreenQmlSurface;
class RenderableWebEntityItem : public WebEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableWebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
~RenderableWebEntityItem();

View file

@ -19,8 +19,8 @@
#include <GeometryCache.h>
#include <PerfStat.h>
EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableZoneEntityItem(entityID, properties);
EntityItemPointer RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableZoneEntityItem(entityID, properties));
}
template<typename Lambda>

View file

@ -19,7 +19,7 @@ class NetworkGeometry;
class RenderableZoneEntityItem : public ZoneEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ZoneEntityItem(entityItemID, properties),

View file

@ -16,7 +16,7 @@
#include "AddEntityOperator.h"
AddEntityOperator::AddEntityOperator(EntityTree* tree,
EntityItem* newEntity) :
EntityItemPointer newEntity) :
_tree(tree),
_newEntity(newEntity),
_foundNew(false),

View file

@ -14,14 +14,14 @@
class AddEntityOperator : public RecurseOctreeOperator {
public:
AddEntityOperator(EntityTree* tree, EntityItem* newEntity);
AddEntityOperator(EntityTree* tree, EntityItemPointer newEntity);
virtual bool preRecursion(OctreeElement* element);
virtual bool postRecursion(OctreeElement* element);
virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex);
private:
EntityTree* _tree;
EntityItem* _newEntity;
EntityItemPointer _newEntity;
bool _foundNew;
quint64 _changeTime;

View file

@ -20,8 +20,8 @@
#include "EntityTreeElement.h"
EntityItem* BoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItem* result = new BoxEntityItem(entityID, properties);
EntityItemPointer BoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result { new BoxEntityItem(entityID, properties) };
return result;
}

View file

@ -16,7 +16,7 @@
class BoxEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);

View file

@ -92,7 +92,7 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) {
// If this is the element we're looking for, then ask it to remove the old entity
// and we can stop searching.
if (entityTreeElement == details.containingElement) {
EntityItem* theEntity = details.entity;
EntityItemPointer theEntity = details.entity;
bool entityDeleted = entityTreeElement->removeEntityItem(theEntity); // remove it from the element
assert(entityDeleted);
_tree->setContainingElement(details.entity->getEntityItemID(), NULL); // update or id to element lookup

View file

@ -14,7 +14,7 @@
class EntityToDeleteDetails {
public:
EntityItem* entity;
EntityItemPointer entity;
AACube cube;
EntityTreeElement* containingElement;
};

View file

@ -318,15 +318,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
return 0;
}
// if this bitstream indicates that this node is the simulation owner, ignore any physics-related updates.
glm::vec3 savePosition = getPosition();
glm::quat saveRotation = getRotation();
// glm::vec3 saveVelocity = _velocity;
// glm::vec3 saveAngularVelocity = _angularVelocity;
// glm::vec3 saveGravity = _gravity;
// glm::vec3 saveAcceleration = _acceleration;
// Header bytes
// object ID [16 bytes]
// ByteCountCoded(type code) [~1 byte]
@ -337,299 +328,308 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
const int MINIMUM_HEADER_BYTES = 27;
int bytesRead = 0;
if (bytesLeftToRead >= MINIMUM_HEADER_BYTES) {
if (bytesLeftToRead < MINIMUM_HEADER_BYTES) {
return 0;
}
int originalLength = bytesLeftToRead;
QByteArray originalDataBuffer((const char*)data, originalLength);
// if this bitstream indicates that this node is the simulation owner, ignore any physics-related updates.
glm::vec3 savePosition = getPosition();
glm::quat saveRotation = getRotation();
glm::vec3 saveVelocity = _velocity;
glm::vec3 saveAngularVelocity = _angularVelocity;
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
int originalLength = bytesLeftToRead;
QByteArray originalDataBuffer((const char*)data, originalLength);
const unsigned char* dataAt = data;
int clockSkew = args.sourceNode ? args.sourceNode->getClockSkewUsec() : 0;
// id
QByteArray encodedID = originalDataBuffer.mid(bytesRead, NUM_BYTES_RFC4122_UUID); // maximum possible size
_id = QUuid::fromRfc4122(encodedID);
dataAt += encodedID.size();
bytesRead += encodedID.size();
// type
QByteArray encodedType = originalDataBuffer.mid(bytesRead); // maximum possible size
ByteCountCoded<quint32> typeCoder = encodedType;
encodedType = typeCoder; // determine true length
dataAt += encodedType.size();
bytesRead += encodedType.size();
quint32 type = typeCoder;
_type = (EntityTypes::EntityType)type;
const unsigned char* dataAt = data;
bool overwriteLocalData = true; // assume the new content overwrites our local data
// id
QByteArray encodedID = originalDataBuffer.mid(bytesRead, NUM_BYTES_RFC4122_UUID); // maximum possible size
_id = QUuid::fromRfc4122(encodedID);
dataAt += encodedID.size();
bytesRead += encodedID.size();
// type
QByteArray encodedType = originalDataBuffer.mid(bytesRead); // maximum possible size
ByteCountCoded<quint32> typeCoder = encodedType;
encodedType = typeCoder; // determine true length
dataAt += encodedType.size();
bytesRead += encodedType.size();
quint32 type = typeCoder;
_type = (EntityTypes::EntityType)type;
// _created
quint64 createdFromBuffer = 0;
memcpy(&createdFromBuffer, dataAt, sizeof(createdFromBuffer));
dataAt += sizeof(createdFromBuffer);
bytesRead += sizeof(createdFromBuffer);
bool overwriteLocalData = true; // assume the new content overwrites our local data
quint64 now = usecTimestampNow();
if (_created == UNKNOWN_CREATED_TIME) {
// we don't yet have a _created timestamp, so we accept this one
createdFromBuffer -= clockSkew;
if (createdFromBuffer > now || createdFromBuffer == UNKNOWN_CREATED_TIME) {
createdFromBuffer = now;
}
_created = createdFromBuffer;
// _created
quint64 createdFromBuffer = 0;
memcpy(&createdFromBuffer, dataAt, sizeof(createdFromBuffer));
dataAt += sizeof(createdFromBuffer);
bytesRead += sizeof(createdFromBuffer);
quint64 now = usecTimestampNow();
if (_created == UNKNOWN_CREATED_TIME) {
// we don't yet have a _created timestamp, so we accept this one
createdFromBuffer -= clockSkew;
if (createdFromBuffer > now || createdFromBuffer == UNKNOWN_CREATED_TIME) {
createdFromBuffer = now;
}
_created = createdFromBuffer;
}
#ifdef WANT_DEBUG
quint64 lastEdited = getLastEdited();
float editedAgo = getEditedAgo();
QString agoAsString = formatSecondsElapsed(editedAgo);
QString ageAsString = formatSecondsElapsed(getAge());
qCDebug(entities) << "------------------------------------------";
qCDebug(entities) << "Loading entity " << getEntityItemID() << " from buffer...";
qCDebug(entities) << "------------------------------------------";
debugDump();
qCDebug(entities) << "------------------------------------------";
qCDebug(entities) << " _created =" << _created;
qCDebug(entities) << " age=" << getAge() << "seconds - " << ageAsString;
qCDebug(entities) << " lastEdited =" << lastEdited;
qCDebug(entities) << " ago=" << editedAgo << "seconds - " << agoAsString;
#endif
quint64 lastEditedFromBuffer = 0;
quint64 lastEditedFromBufferAdjusted = 0;
// TODO: we could make this encoded as a delta from _created
// _lastEdited
memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer));
dataAt += sizeof(lastEditedFromBuffer);
bytesRead += sizeof(lastEditedFromBuffer);
lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
if (lastEditedFromBufferAdjusted > now) {
lastEditedFromBufferAdjusted = now;
}
bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime);
#ifdef WANT_DEBUG
qCDebug(entities) << "data from server **************** ";
qCDebug(entities) << " entityItemID:" << getEntityItemID();
qCDebug(entities) << " now:" << now;
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " lastEditedFromBuffer:" << debugTime(lastEditedFromBuffer, now);
qCDebug(entities) << " clockSkew:" << debugTimeOnly(clockSkew);
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
qCDebug(entities) << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, now);
qCDebug(entities) << " _lastEditedFromRemoteInRemoteTime:" << debugTime(_lastEditedFromRemoteInRemoteTime, now);
qCDebug(entities) << " fromSameServerEdit:" << fromSameServerEdit;
#endif
bool ignoreServerPacket = false; // assume we'll use this server packet
// If this packet is from the same server edit as the last packet we accepted from the server
// we probably want to use it.
if (fromSameServerEdit) {
// If this is from the same sever packet, then check against any local changes since we got
// the most recent packet from this server time
if (_lastEdited > _lastEditedFromRemote) {
ignoreServerPacket = true;
}
} else {
// If this isn't from the same sever packet, then honor our skew adjusted times...
// If we've changed our local tree more recently than the new data from this packet
// then we will not be changing our values, instead we just read and skip the data
if (_lastEdited > lastEditedFromBufferAdjusted) {
ignoreServerPacket = true;
}
}
if (ignoreServerPacket) {
overwriteLocalData = false;
#ifdef WANT_DEBUG
quint64 lastEdited = getLastEdited();
float editedAgo = getEditedAgo();
QString agoAsString = formatSecondsElapsed(editedAgo);
QString ageAsString = formatSecondsElapsed(getAge());
qCDebug(entities) << "------------------------------------------";
qCDebug(entities) << "Loading entity " << getEntityItemID() << " from buffer...";
qCDebug(entities) << "------------------------------------------";
qCDebug(entities) << "IGNORING old data from server!!! ****************";
debugDump();
qCDebug(entities) << "------------------------------------------";
qCDebug(entities) << " _created =" << _created;
qCDebug(entities) << " age=" << getAge() << "seconds - " << ageAsString;
qCDebug(entities) << " lastEdited =" << lastEdited;
qCDebug(entities) << " ago=" << editedAgo << "seconds - " << agoAsString;
#endif
quint64 lastEditedFromBuffer = 0;
quint64 lastEditedFromBufferAdjusted = 0;
// TODO: we could make this encoded as a delta from _created
// _lastEdited
memcpy(&lastEditedFromBuffer, dataAt, sizeof(lastEditedFromBuffer));
dataAt += sizeof(lastEditedFromBuffer);
bytesRead += sizeof(lastEditedFromBuffer);
lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
if (lastEditedFromBufferAdjusted > now) {
lastEditedFromBufferAdjusted = now;
}
bool fromSameServerEdit = (lastEditedFromBuffer == _lastEditedFromRemoteInRemoteTime);
} else {
#ifdef WANT_DEBUG
qCDebug(entities) << "data from server **************** ";
qCDebug(entities) << " entityItemID:" << getEntityItemID();
qCDebug(entities) << " now:" << now;
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " lastEditedFromBuffer:" << debugTime(lastEditedFromBuffer, now);
qCDebug(entities) << " clockSkew:" << debugTimeOnly(clockSkew);
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
qCDebug(entities) << " _lastEditedFromRemote:" << debugTime(_lastEditedFromRemote, now);
qCDebug(entities) << " _lastEditedFromRemoteInRemoteTime:" << debugTime(_lastEditedFromRemoteInRemoteTime, now);
qCDebug(entities) << " fromSameServerEdit:" << fromSameServerEdit;
qCDebug(entities) << "USING NEW data from server!!! ****************";
debugDump();
#endif
bool ignoreServerPacket = false; // assume we'll use this server packet
// If this packet is from the same server edit as the last packet we accepted from the server
// we probably want to use it.
if (fromSameServerEdit) {
// If this is from the same sever packet, then check against any local changes since we got
// the most recent packet from this server time
if (_lastEdited > _lastEditedFromRemote) {
ignoreServerPacket = true;
}
} else {
// If this isn't from the same sever packet, then honor our skew adjusted times...
// If we've changed our local tree more recently than the new data from this packet
// then we will not be changing our values, instead we just read and skip the data
if (_lastEdited > lastEditedFromBufferAdjusted) {
ignoreServerPacket = true;
}
}
// don't allow _lastEdited to be in the future
_lastEdited = lastEditedFromBufferAdjusted;
_lastEditedFromRemote = now;
_lastEditedFromRemoteInRemoteTime = lastEditedFromBuffer;
if (ignoreServerPacket) {
overwriteLocalData = false;
#ifdef WANT_DEBUG
qCDebug(entities) << "IGNORING old data from server!!! ****************";
debugDump();
#endif
} else {
// TODO: only send this notification if something ACTUALLY changed (hint, we haven't yet parsed
// the properties out of the bitstream (see below))
somethingChangedNotification(); // notify derived classes that something has changed
}
#ifdef WANT_DEBUG
qCDebug(entities) << "USING NEW data from server!!! ****************";
debugDump();
#endif
// don't allow _lastEdited to be in the future
_lastEdited = lastEditedFromBufferAdjusted;
_lastEditedFromRemote = now;
_lastEditedFromRemoteInRemoteTime = lastEditedFromBuffer;
// TODO: only send this notification if something ACTUALLY changed (hint, we haven't yet parsed
// the properties out of the bitstream (see below))
somethingChangedNotification(); // notify derived classes that something has changed
}
// last updated is stored as ByteCountCoded delta from lastEdited
QByteArray encodedUpdateDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
quint64 updateDelta = updateDeltaCoder;
// last updated is stored as ByteCountCoded delta from lastEdited
QByteArray encodedUpdateDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
quint64 updateDelta = updateDeltaCoder;
if (overwriteLocalData) {
_lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that
#ifdef WANT_DEBUG
qCDebug(entities) << " _lastUpdated:" << debugTime(_lastUpdated, now);
qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now);
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
#endif
}
encodedUpdateDelta = updateDeltaCoder; // determine true length
dataAt += encodedUpdateDelta.size();
bytesRead += encodedUpdateDelta.size();
// Newer bitstreams will have a last simulated and a last updated value
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) {
// last simulated is stored as ByteCountCoded delta from lastEdited
QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
ByteCountCoded<quint64> simulatedDeltaCoder = encodedSimulatedDelta;
quint64 simulatedDelta = simulatedDeltaCoder;
if (overwriteLocalData) {
_lastUpdated = lastEditedFromBufferAdjusted + updateDelta; // don't adjust for clock skew since we already did that
_lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that
#ifdef WANT_DEBUG
qCDebug(entities) << " _lastUpdated:" << debugTime(_lastUpdated, now);
qCDebug(entities) << " _lastSimulated:" << debugTime(_lastSimulated, now);
qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now);
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
#endif
}
encodedUpdateDelta = updateDeltaCoder; // determine true length
dataAt += encodedUpdateDelta.size();
bytesRead += encodedUpdateDelta.size();
// Newer bitstreams will have a last simulated and a last updated value
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME) {
// last simulated is stored as ByteCountCoded delta from lastEdited
QByteArray encodedSimulatedDelta = originalDataBuffer.mid(bytesRead); // maximum possible size
ByteCountCoded<quint64> simulatedDeltaCoder = encodedSimulatedDelta;
quint64 simulatedDelta = simulatedDeltaCoder;
encodedSimulatedDelta = simulatedDeltaCoder; // determine true length
dataAt += encodedSimulatedDelta.size();
bytesRead += encodedSimulatedDelta.size();
}
#ifdef WANT_DEBUG
if (overwriteLocalData) {
qCDebug(entities) << "EntityItem::readEntityDataFromBuffer()... changed entity:" << getEntityItemID();
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " getLastSimulated:" << debugTime(getLastSimulated(), now);
qCDebug(entities) << " getLastUpdated:" << debugTime(getLastUpdated(), now);
}
#endif
// Property Flags
QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
dataAt += propertyFlags.getEncodedLength();
bytesRead += propertyFlags.getEncodedLength();
bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS);
if (useMeters) {
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
} else {
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionInDomainUnits);
}
// Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) {
if (propertyFlags.getHasProperty(PROP_RADIUS)) {
float fromBuffer;
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer));
dataAt += sizeof(fromBuffer);
bytesRead += sizeof(fromBuffer);
if (overwriteLocalData) {
_lastSimulated = lastEditedFromBufferAdjusted + simulatedDelta; // don't adjust for clock skew since we already did that
#ifdef WANT_DEBUG
qCDebug(entities) << " _lastSimulated:" << debugTime(_lastSimulated, now);
qCDebug(entities) << " _lastEdited:" << debugTime(_lastEdited, now);
qCDebug(entities) << " lastEditedFromBufferAdjusted:" << debugTime(lastEditedFromBufferAdjusted, now);
#endif
setRadius(fromBuffer);
}
encodedSimulatedDelta = simulatedDeltaCoder; // determine true length
dataAt += encodedSimulatedDelta.size();
bytesRead += encodedSimulatedDelta.size();
}
#ifdef WANT_DEBUG
if (overwriteLocalData) {
qCDebug(entities) << "EntityItem::readEntityDataFromBuffer()... changed entity:" << getEntityItemID();
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << " getLastSimulated:" << debugTime(getLastSimulated(), now);
qCDebug(entities) << " getLastUpdated:" << debugTime(getLastUpdated(), now);
}
#endif
// Property Flags
QByteArray encodedPropertyFlags = originalDataBuffer.mid(bytesRead); // maximum possible size
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
dataAt += propertyFlags.getEncodedLength();
bytesRead += propertyFlags.getEncodedLength();
bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS);
} else {
if (useMeters) {
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
} else {
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionInDomainUnits);
}
// Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) {
if (propertyFlags.getHasProperty(PROP_RADIUS)) {
float fromBuffer;
memcpy(&fromBuffer, dataAt, sizeof(fromBuffer));
dataAt += sizeof(fromBuffer);
bytesRead += sizeof(fromBuffer);
if (overwriteLocalData) {
setRadius(fromBuffer);
}
}
} else {
if (useMeters) {
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
} else {
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensionsInDomainUnits);
}
}
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
if (useMeters) {
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity);
} else {
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocityInDomainUnits);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravityInDomainUnits);
}
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration);
}
READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping);
READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution);
READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction);
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
if (useMeters) {
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
} else {
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees);
}
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping);
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions);
READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove);
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked);
READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData);
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
READ_ENTITY_PROPERTY(PROP_SIMULATOR_ID, QUuid, updateSimulatorID);
}
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) {
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
}
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
////////////////////////////////////
// WARNING: Do not add stream content here after the subclass. Always add it before the subclass
//
// NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover
// by doing this parsing here... but it's not likely going to fully recover the content.
//
// TODO: Remove this conde once we've sufficiently migrated content past this damaged version
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) {
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
}
if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES))) {
// NOTE: This code is attempting to "repair" the old data we just got from the server to make it more
// closely match where the entities should be if they'd stepped forward in time to "now". The server
// is sending us data with a known "last simulated" time. That time is likely in the past, and therefore
// this "new" data is actually slightly out of date. We calculate the time we need to skip forward and
// use our simulation helper routine to get a best estimate of where the entity should be.
const float MIN_TIME_SKIP = 0.0f;
const float MAX_TIME_SKIP = 1.0f; // in seconds
float skipTimeForward = glm::clamp((float)(now - _lastSimulated) / (float)(USECS_PER_SECOND),
MIN_TIME_SKIP, MAX_TIME_SKIP);
if (skipTimeForward > 0.0f) {
#ifdef WANT_DEBUG
qCDebug(entities) << "skipTimeForward:" << skipTimeForward;
#endif
// we want to extrapolate the motion forward to compensate for packet travel time, but
// we don't want the side effect of flag setting.
simulateKinematicMotion(skipTimeForward, false);
}
_lastSimulated = now;
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensionsInDomainUnits);
}
}
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
if (useMeters) {
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity);
} else {
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocityInDomainUnits);
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravityInDomainUnits);
}
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration);
}
READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping);
READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution);
READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction);
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
if (useMeters) {
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
} else {
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees);
}
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping);
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions);
READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove);
READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked);
READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData);
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
// we always accept the server's notion of simulatorID, so we fake overwriteLocalData as true
// before we try to READ_ENTITY_PROPERTY it
bool temp = overwriteLocalData;
overwriteLocalData = true;
READ_ENTITY_PROPERTY(PROP_SIMULATOR_ID, QUuid, updateSimulatorID);
overwriteLocalData = temp;
}
if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) {
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
}
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
////////////////////////////////////
// WARNING: Do not add stream content here after the subclass. Always add it before the subclass
//
// NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover
// by doing this parsing here... but it's not likely going to fully recover the content.
//
// TODO: Remove this conde once we've sufficiently migrated content past this damaged version
if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) {
READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
}
if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES))) {
// NOTE: This code is attempting to "repair" the old data we just got from the server to make it more
// closely match where the entities should be if they'd stepped forward in time to "now". The server
// is sending us data with a known "last simulated" time. That time is likely in the past, and therefore
// this "new" data is actually slightly out of date. We calculate the time we need to skip forward and
// use our simulation helper routine to get a best estimate of where the entity should be.
const float MIN_TIME_SKIP = 0.0f;
const float MAX_TIME_SKIP = 1.0f; // in seconds
float skipTimeForward = glm::clamp((float)(now - _lastSimulated) / (float)(USECS_PER_SECOND),
MIN_TIME_SKIP, MAX_TIME_SKIP);
if (skipTimeForward > 0.0f) {
#ifdef WANT_DEBUG
qCDebug(entities) << "skipTimeForward:" << skipTimeForward;
#endif
// we want to extrapolate the motion forward to compensate for packet travel time, but
// we don't want the side effect of flag setting.
simulateKinematicMotion(skipTimeForward, false);
}
_lastSimulated = now;
}
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID();
if (_simulatorID == myNodeID && !_simulatorID.isNull()) {
// the packet that produced this bitstream originally came from physics simulations performed by
// this node, so our version has to be newer than what the packet contained.
if (overwriteLocalData && _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
setPosition(savePosition);
setRotation(saveRotation);
// _velocity = saveVelocity;
// _angularVelocity = saveAngularVelocity;
// _gravity = saveGravity;
// _acceleration = saveAcceleration;
_velocity = saveVelocity;
_angularVelocity = saveAngularVelocity;
_dirtyFlags &= ~(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES);
}
return bytesRead;
@ -949,40 +949,25 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
if (somethingChanged) {
somethingChangedNotification(); // notify derived classes that something has changed
uint64_t now = usecTimestampNow();
#ifdef WANT_DEBUG
int elapsed = now - getLastEdited();
qCDebug(entities) << "EntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " getLastEdited()=" << getLastEdited();
#endif
if (_created != UNKNOWN_CREATED_TIME) {
setLastEdited(now);
setLastEdited(now);
somethingChangedNotification(); // notify derived classes that something has changed
if (_created == UNKNOWN_CREATED_TIME) {
_created = now;
}
if (getDirtyFlags() & (EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES)) {
// TODO: Andrew & Brad to discuss. Is this correct? Maybe it is. Need to think through all cases.
// anything that sets the transform or velocity must update _lastSimulated which is used
// for kinematic extrapolation (e.g. we want to extrapolate forward from this moment
// when position and/or velocity was changed).
_lastSimulated = now;
}
}
// timestamps
quint64 timestamp = properties.getCreated();
if (_created == UNKNOWN_CREATED_TIME && timestamp != UNKNOWN_CREATED_TIME) {
quint64 now = usecTimestampNow();
if (timestamp > now) {
timestamp = now;
}
_created = timestamp;
timestamp = properties.getLastEdited();
if (timestamp > now) {
timestamp = now;
} else if (timestamp < _created) {
timestamp = _created;
}
_lastEdited = timestamp;
}
return somethingChanged;
}

View file

@ -78,7 +78,7 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties
bool success = true;
if (_entityTree) {
_entityTree->lockForWrite();
EntityItem* entity = _entityTree->addEntity(id, propertiesWithSimID);
EntityItemPointer entity = _entityTree->addEntity(id, propertiesWithSimID);
if (entity) {
entity->setLastBroadcast(usecTimestampNow());
// This Node is creating a new object. If it's in motion, set this Node as the simulator.
@ -102,7 +102,8 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
EntityItemProperties results;
if (_entityTree) {
_entityTree->lockForRead();
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(EntityItemID(identity)));
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity));
if (entity) {
results = entity->getProperties();
@ -137,7 +138,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
// make sure the properties has a type, so that the encode can know which properties to include
if (properties.getType() == EntityTypes::Unknown) {
EntityItem* entity = _entityTree->findEntityByEntityItemID(entityID);
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
if (entity) {
// we need to change the outgoing properties, so we make a copy, modify, and send.
EntityItemProperties modifiedProperties = properties;
@ -161,7 +162,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
if (_entityTree) {
_entityTree->lockForWrite();
EntityItem* entity = const_cast<EntityItem*>(_entityTree->findEntityByEntityItemID(entityID));
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
if (entity) {
if (entity->getLocked()) {
shouldDelete = false;
@ -183,7 +184,7 @@ QUuid EntityScriptingInterface::findClosestEntity(const glm::vec3& center, float
EntityItemID result;
if (_entityTree) {
_entityTree->lockForRead();
const EntityItem* closestEntity = _entityTree->findClosestEntity(center, radius);
EntityItemPointer closestEntity = _entityTree->findClosestEntity(center, radius);
_entityTree->unlock();
if (closestEntity) {
result = closestEntity->getEntityItemID();
@ -205,11 +206,11 @@ QVector<QUuid> EntityScriptingInterface::findEntities(const glm::vec3& center, f
QVector<QUuid> result;
if (_entityTree) {
_entityTree->lockForRead();
QVector<const EntityItem*> entities;
QVector<EntityItemPointer> entities;
_entityTree->findEntities(center, radius, entities);
_entityTree->unlock();
foreach (const EntityItem* entity, entities) {
foreach (EntityItemPointer entity, entities) {
result << entity->getEntityItemID();
}
}
@ -221,11 +222,11 @@ QVector<QUuid> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corn
if (_entityTree) {
_entityTree->lockForRead();
AABox box(corner, dimensions);
QVector<EntityItem*> entities;
QVector<EntityItemPointer> entities;
_entityTree->findEntities(box, entities);
_entityTree->unlock();
foreach (const EntityItem* entity, entities) {
foreach (EntityItemPointer entity, entities) {
result << entity->getEntityItemID();
}
}
@ -248,7 +249,7 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorke
RayToEntityIntersectionResult result;
if (_entityTree) {
OctreeElement* element;
EntityItem* intersectedEntity = NULL;
EntityItemPointer intersectedEntity = NULL;
result.intersects = _entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
(void**)&intersectedEntity, lockType, &result.accurate,
precisionPicking);

View file

@ -39,7 +39,7 @@ public:
float distance;
BoxFace face;
glm::vec3 intersection;
EntityItem* entity;
EntityItemPointer entity;
};
Q_DECLARE_METATYPE(RayToEntityIntersectionResult)
@ -121,6 +121,7 @@ public slots:
signals:
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
void canAdjustLocksChanged(bool canAdjustLocks);
void canRezChanged(bool canRez);

View file

@ -38,22 +38,21 @@ void EntitySimulation::updateEntities() {
}
void EntitySimulation::getEntitiesToDelete(VectorOfEntities& entitiesToDelete) {
for (auto entityItr : _entitiesToDelete) {
EntityItem* entity = &(*entityItr);
for (auto entity : _entitiesToDelete) {
// this entity is still in its tree, so we insert into the external list
entitiesToDelete.push_back(entity);
++entityItr;
}
_entitiesToDelete.clear();
}
void EntitySimulation::addEntityInternal(EntityItem* entity) {
void EntitySimulation::addEntityInternal(EntityItemPointer entity) {
if (entity->isMoving() && !entity->getPhysicsInfo()) {
_simpleKinematicEntities.insert(entity);
}
}
void EntitySimulation::changeEntityInternal(EntityItem* entity) {
void EntitySimulation::changeEntityInternal(EntityItemPointer entity) {
if (entity->isMoving() && !entity->getPhysicsInfo()) {
_simpleKinematicEntities.insert(entity);
} else {
@ -68,7 +67,7 @@ void EntitySimulation::expireMortalEntities(const quint64& now) {
_nextExpiry = quint64(-1);
SetOfEntities::iterator itemItr = _mortalEntities.begin();
while (itemItr != _mortalEntities.end()) {
EntityItem* entity = *itemItr;
EntityItemPointer entity = *itemItr;
quint64 expiry = entity->getExpiry();
if (expiry < now) {
_entitiesToDelete.insert(entity);
@ -96,7 +95,7 @@ void EntitySimulation::callUpdateOnEntitiesThatNeedIt(const quint64& now) {
PerformanceTimer perfTimer("updatingEntities");
SetOfEntities::iterator itemItr = _entitiesToUpdate.begin();
while (itemItr != _entitiesToUpdate.end()) {
EntityItem* entity = *itemItr;
EntityItemPointer entity = *itemItr;
// TODO: catch transition from needing update to not as a "change"
// so we don't have to scan for it here.
if (!entity->needsToCallUpdate()) {
@ -117,7 +116,7 @@ void EntitySimulation::sortEntitiesThatMoved() {
AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), (float)TREE_SCALE);
SetOfEntities::iterator itemItr = _entitiesToSort.begin();
while (itemItr != _entitiesToSort.end()) {
EntityItem* entity = *itemItr;
EntityItemPointer entity = *itemItr;
// check to see if this movement has sent the entity outside of the domain.
AACube newCube = entity->getMaximumAACube();
if (!domainBounds.touches(newCube)) {
@ -145,7 +144,7 @@ void EntitySimulation::sortEntitiesThatMoved() {
_entitiesToSort.clear();
}
void EntitySimulation::addEntity(EntityItem* entity) {
void EntitySimulation::addEntity(EntityItemPointer entity) {
assert(entity);
if (entity->isMortal()) {
_mortalEntities.insert(entity);
@ -167,7 +166,7 @@ void EntitySimulation::addEntity(EntityItem* entity) {
entity->clearDirtyFlags();
}
void EntitySimulation::removeEntity(EntityItem* entity) {
void EntitySimulation::removeEntity(EntityItemPointer entity) {
assert(entity);
_entitiesToUpdate.remove(entity);
_mortalEntities.remove(entity);
@ -180,7 +179,7 @@ void EntitySimulation::removeEntity(EntityItem* entity) {
entity->_simulated = false;
}
void EntitySimulation::changeEntity(EntityItem* entity) {
void EntitySimulation::changeEntity(EntityItemPointer entity) {
assert(entity);
if (!entity->_simulated) {
// This entity was either never added to the simulation or has been removed
@ -250,7 +249,7 @@ void EntitySimulation::clearEntities() {
void EntitySimulation::moveSimpleKinematics(const quint64& now) {
SetOfEntities::iterator itemItr = _simpleKinematicEntities.begin();
while (itemItr != _simpleKinematicEntities.end()) {
EntityItem* entity = *itemItr;
EntityItemPointer entity = *itemItr;
if (entity->isMoving() && !entity->getPhysicsInfo()) {
entity->simulate(now);
_entitiesToSort.insert(entity);

View file

@ -21,8 +21,8 @@
#include "EntityItem.h"
#include "EntityTree.h"
typedef QSet<EntityItem*> SetOfEntities;
typedef QVector<EntityItem*> VectorOfEntities;
typedef QSet<EntityItemPointer> SetOfEntities;
typedef QVector<EntityItemPointer> VectorOfEntities;
// the EntitySimulation needs to know when these things change on an entity,
// so it can sort EntityItem or relay its state to the PhysicsEngine.
@ -59,16 +59,16 @@ public:
protected: // these only called by the EntityTree?
/// \param entity pointer to EntityItem to be added
/// \sideeffect sets relevant backpointers in entity, but maybe later when appropriate data structures are locked
void addEntity(EntityItem* entity);
void addEntity(EntityItemPointer entity);
/// \param entity pointer to EntityItem to be removed
/// \brief the actual removal may happen later when appropriate data structures are locked
/// \sideeffect nulls relevant backpointers in entity
void removeEntity(EntityItem* entity);
void removeEntity(EntityItemPointer entity);
/// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation
/// call this whenever an entity was changed from some EXTERNAL event (NOT by the EntitySimulation itself)
void changeEntity(EntityItem* entity);
void changeEntity(EntityItemPointer entity);
void clearEntities();
@ -88,9 +88,9 @@ protected:
// These pure virtual methods are protected because they are not to be called will-nilly. The base class
// calls them in the right places.
virtual void updateEntitiesInternal(const quint64& now) = 0;
virtual void addEntityInternal(EntityItem* entity);
virtual void removeEntityInternal(EntityItem* entity) = 0;
virtual void changeEntityInternal(EntityItem* entity);
virtual void addEntityInternal(EntityItemPointer entity);
virtual void removeEntityInternal(EntityItemPointer entity) = 0;
virtual void changeEntityInternal(EntityItemPointer entity);
virtual void clearEntitiesInternal() = 0;
void expireMortalEntities(const quint64& now);

View file

@ -75,7 +75,7 @@ bool EntityTree::handlesEditPacketType(PacketType packetType) const {
}
/// Adds a new entity item to the tree
void EntityTree::postAddEntity(EntityItem* entity) {
void EntityTree::postAddEntity(EntityItemPointer entity) {
assert(entity);
// check to see if we need to simulate this entity..
if (_simulation) {
@ -94,7 +94,7 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp
return false;
}
EntityItem* existingEntity = containingElement->getEntityWithEntityItemID(entityID);
EntityItemPointer existingEntity = containingElement->getEntityWithEntityItemID(entityID);
if (!existingEntity) {
qCDebug(entities) << "UNEXPECTED!!!! don't call updateEntity() on entity items that don't exist. entityID=" << entityID;
return false;
@ -103,7 +103,7 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp
return updateEntityWithElement(existingEntity, properties, containingElement, senderNode);
}
bool EntityTree::updateEntity(EntityItem* entity, const EntityItemProperties& properties, const SharedNodePointer& senderNode) {
bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperties& properties, const SharedNodePointer& senderNode) {
EntityTreeElement* containingElement = getContainingElement(entity->getEntityItemID());
if (!containingElement) {
qCDebug(entities) << "UNEXPECTED!!!! EntityTree::updateEntity() entity-->element lookup failed!!! entityID="
@ -113,7 +113,7 @@ bool EntityTree::updateEntity(EntityItem* entity, const EntityItemProperties& pr
return updateEntityWithElement(entity, properties, containingElement, senderNode);
}
bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemProperties& origProperties,
bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityItemProperties& origProperties,
EntityTreeElement* containingElement, const SharedNodePointer& senderNode) {
EntityItemProperties properties = origProperties;
@ -220,8 +220,8 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
return true;
}
EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItem* result = NULL;
EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result = NULL;
if (getIsClient()) {
// if our Node isn't allowed to create entities in this domain, don't try.
@ -291,7 +291,7 @@ void EntityTree::deleteEntity(const EntityItemID& entityID, bool force, bool ign
return;
}
EntityItem* existingEntity = containingElement->getEntityWithEntityItemID(entityID);
EntityItemPointer existingEntity = containingElement->getEntityWithEntityItemID(entityID);
if (!existingEntity) {
if (!ignoreWarnings) {
qCDebug(entities) << "UNEXPECTED!!!! don't call EntityTree::deleteEntity() on entity items that don't exist. "
@ -328,7 +328,7 @@ void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs, bool force, bool i
continue;
}
EntityItem* existingEntity = containingElement->getEntityWithEntityItemID(entityID);
EntityItemPointer existingEntity = containingElement->getEntityWithEntityItemID(entityID);
if (!existingEntity) {
if (!ignoreWarnings) {
qCDebug(entities) << "UNEXPECTED!!!! don't call EntityTree::deleteEntities() on entity items that don't exist. "
@ -362,7 +362,7 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator)
_simulation->lock();
}
foreach(const EntityToDeleteDetails& details, entities) {
EntityItem* theEntity = details.entity;
EntityItemPointer theEntity = details.entity;
if (getIsServer()) {
// set up the deleted entities ID
@ -374,8 +374,7 @@ void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator)
if (_simulation) {
_simulation->removeEntity(theEntity);
}
delete theEntity; // we can delete the entity immediately
}
}
if (_simulation) {
_simulation->unlock();
@ -388,7 +387,7 @@ public:
glm::vec3 position;
float targetRadius;
bool found;
const EntityItem* closestEntity;
EntityItemPointer closestEntity;
float closestEntityDistance;
};
@ -402,7 +401,7 @@ bool EntityTree::findNearPointOperation(OctreeElement* element, void* extraData)
// If this entityTreeElement contains the point, then search it...
if (sphereIntersection) {
const EntityItem* thisClosestEntity = entityTreeElement->getClosestEntity(args->position);
EntityItemPointer thisClosestEntity = entityTreeElement->getClosestEntity(args->position);
// we may have gotten NULL back, meaning no entity was available
if (thisClosestEntity) {
@ -428,7 +427,7 @@ bool EntityTree::findNearPointOperation(OctreeElement* element, void* extraData)
return false;
}
const EntityItem* EntityTree::findClosestEntity(glm::vec3 position, float targetRadius) {
EntityItemPointer EntityTree::findClosestEntity(glm::vec3 position, float targetRadius) {
FindNearPointArgs args = { position, targetRadius, false, NULL, FLT_MAX };
lockForRead();
// NOTE: This should use recursion, since this is a spatial operation
@ -441,7 +440,7 @@ class FindAllNearPointArgs {
public:
glm::vec3 position;
float targetRadius;
QVector<const EntityItem*> entities;
QVector<EntityItemPointer> entities;
};
@ -462,8 +461,8 @@ bool EntityTree::findInSphereOperation(OctreeElement* element, void* extraData)
}
// NOTE: assumes caller has handled locking
void EntityTree::findEntities(const glm::vec3& center, float radius, QVector<const EntityItem*>& foundEntities) {
FindAllNearPointArgs args = { center, radius, QVector<const EntityItem*>() };
void EntityTree::findEntities(const glm::vec3& center, float radius, QVector<EntityItemPointer>& foundEntities) {
FindAllNearPointArgs args = { center, radius, QVector<EntityItemPointer>() };
// NOTE: This should use recursion, since this is a spatial operation
recurseTreeWithOperation(findInSphereOperation, &args);
@ -478,7 +477,7 @@ public:
}
AACube _cube;
QVector<EntityItem*> _foundEntities;
QVector<EntityItemPointer> _foundEntities;
};
bool EntityTree::findInCubeOperation(OctreeElement* element, void* extraData) {
@ -492,7 +491,7 @@ bool EntityTree::findInCubeOperation(OctreeElement* element, void* extraData) {
}
// NOTE: assumes caller has handled locking
void EntityTree::findEntities(const AACube& cube, QVector<EntityItem*>& foundEntities) {
void EntityTree::findEntities(const AACube& cube, QVector<EntityItemPointer>& foundEntities) {
FindEntitiesInCubeArgs args(cube);
// NOTE: This should use recursion, since this is a spatial operation
recurseTreeWithOperation(findInCubeOperation, &args);
@ -507,7 +506,7 @@ public:
}
AABox _box;
QVector<EntityItem*> _foundEntities;
QVector<EntityItemPointer> _foundEntities;
};
bool EntityTree::findInBoxOperation(OctreeElement* element, void* extraData) {
@ -521,7 +520,7 @@ bool EntityTree::findInBoxOperation(OctreeElement* element, void* extraData) {
}
// NOTE: assumes caller has handled locking
void EntityTree::findEntities(const AABox& box, QVector<EntityItem*>& foundEntities) {
void EntityTree::findEntities(const AABox& box, QVector<EntityItemPointer>& foundEntities) {
FindEntitiesInBoxArgs args(box);
// NOTE: This should use recursion, since this is a spatial operation
recurseTreeWithOperation(findInBoxOperation, &args);
@ -529,13 +528,13 @@ void EntityTree::findEntities(const AABox& box, QVector<EntityItem*>& foundEntit
foundEntities.swap(args._foundEntities);
}
EntityItem* EntityTree::findEntityByID(const QUuid& id) {
EntityItemPointer EntityTree::findEntityByID(const QUuid& id) {
EntityItemID entityID(id);
return findEntityByEntityItemID(entityID);
}
EntityItem* EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) /*const*/ {
EntityItem* foundEntity = NULL;
EntityItemPointer EntityTree::findEntityByEntityItemID(const EntityItemID& entityID) /*const*/ {
EntityItemPointer foundEntity = NULL;
EntityTreeElement* containingElement = getContainingElement(entityID);
if (containingElement) {
foundEntity = containingElement->getEntityWithEntityItemID(entityID);
@ -571,7 +570,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
// an existing entity... handle appropriately
if (validEditPacket) {
// search for the entity by EntityItemID
EntityItem* existingEntity = findEntityByEntityItemID(entityItemID);
EntityItemPointer existingEntity = findEntityByEntityItemID(entityItemID);
if (existingEntity && packetType == PacketTypeEntityEdit) {
// if the EntityItem exists, then update it
if (wantEditLogging()) {
@ -588,7 +587,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
qCDebug(entities) << " properties:" << properties;
}
properties.setCreated(properties.getLastEdited());
EntityItem* newEntity = addEntity(entityItemID, properties);
EntityItemPointer newEntity = addEntity(entityItemID, properties);
if (newEntity) {
newEntity->markAsChangedOnServer();
notifyNewlyCreatedEntity(*newEntity, senderNode);
@ -604,7 +603,7 @@ int EntityTree::processEditPacketData(PacketType packetType, const unsigned char
<< "] attempted to add an entity.";
}
} else {
qCDebug(entities) << "Add or Edit failed." << packetType << existingEntity;
qCDebug(entities) << "Add or Edit failed." << packetType << existingEntity.get();
}
}
break;
@ -652,7 +651,7 @@ void EntityTree::releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncod
extraEncodeData->clear();
}
void EntityTree::entityChanged(EntityItem* entity) {
void EntityTree::entityChanged(EntityItemPointer entity) {
if (_simulation) {
_simulation->lock();
_simulation->changeEntity(entity);
@ -672,11 +671,12 @@ void EntityTree::update() {
if (pendingDeletes.size() > 0) {
// translate into list of ID's
QSet<EntityItemID> idsToDelete;
for (auto entityItr : pendingDeletes) {
EntityItem* entity = &(*entityItr);
for (auto entity : pendingDeletes) {
assert(!entity->getPhysicsInfo()); // TODO: Andrew to remove this after testing
idsToDelete.insert(entity->getEntityItemID());
}
// delete these things the roundabout way
deleteEntities(idsToDelete, true);
}
@ -1004,7 +1004,7 @@ bool EntityTree::sendEntitiesOperation(OctreeElement* element, void* extraData)
SendEntitiesOperationArgs* args = static_cast<SendEntitiesOperationArgs*>(extraData);
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
const QList<EntityItem*>& entities = entityTreeElement->getEntities();
const EntityItems& entities = entityTreeElement->getEntities();
for (int i = 0; i < entities.size(); i++) {
EntityItemID newID(QUuid::createUuid());
args->newEntityIDs->append(newID);
@ -1056,7 +1056,7 @@ bool EntityTree::readFromMap(QVariantMap& map) {
entityItemID = EntityItemID(QUuid::createUuid());
}
EntityItem* entity = addEntity(entityItemID, properties);
EntityItemPointer entity = addEntity(entityItemID, properties);
if (!entity) {
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();
}

View file

@ -30,9 +30,9 @@ public:
class EntityItemFBXService {
public:
virtual const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem) = 0;
virtual const Model* getModelForEntityItem(const EntityItem* entityItem) = 0;
virtual const FBXGeometry* getCollisionGeometryForEntity(const EntityItem* entityItem) = 0;
virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) = 0;
virtual const Model* getModelForEntityItem(EntityItemPointer entityItem) = 0;
virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem) = 0;
};
@ -83,24 +83,24 @@ public:
virtual void update();
// The newer API...
void postAddEntity(EntityItem* entityItem);
void postAddEntity(EntityItemPointer entityItem);
EntityItem* addEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
EntityItemPointer addEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
// use this method if you only know the entityID
bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
// use this method if you have a pointer to the entity (avoid an extra entity lookup)
bool updateEntity(EntityItem* entity, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
bool updateEntity(EntityItemPointer entity, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = false);
void deleteEntities(QSet<EntityItemID> entityIDs, bool force = false, bool ignoreWarnings = false);
/// \param position point of query in world-frame (meters)
/// \param targetRadius radius of query (meters)
const EntityItem* findClosestEntity(glm::vec3 position, float targetRadius);
EntityItem* findEntityByID(const QUuid& id);
EntityItem* findEntityByEntityItemID(const EntityItemID& entityID);
EntityItemPointer findClosestEntity(glm::vec3 position, float targetRadius);
EntityItemPointer findEntityByID(const QUuid& id);
EntityItemPointer findEntityByEntityItemID(const EntityItemID& entityID);
EntityItemID assignEntityID(const EntityItemID& entityItemID); /// Assigns a known ID for a creator token ID
@ -108,21 +108,21 @@ public:
/// finds all entities that touch a sphere
/// \param center the center of the sphere in world-frame (meters)
/// \param radius the radius of the sphere in world-frame (meters)
/// \param foundEntities[out] vector of const EntityItem*
/// \param foundEntities[out] vector of EntityItemPointer
/// \remark Side effect: any initial contents in foundEntities will be lost
void findEntities(const glm::vec3& center, float radius, QVector<const EntityItem*>& foundEntities);
void findEntities(const glm::vec3& center, float radius, QVector<EntityItemPointer>& foundEntities);
/// finds all entities that touch a cube
/// \param cube the query cube in world-frame (meters)
/// \param foundEntities[out] vector of non-const EntityItem*
/// \param foundEntities[out] vector of non-EntityItemPointer
/// \remark Side effect: any initial contents in entities will be lost
void findEntities(const AACube& cube, QVector<EntityItem*>& foundEntities);
void findEntities(const AACube& cube, QVector<EntityItemPointer>& foundEntities);
/// finds all entities that touch a box
/// \param box the query box in world-frame (meters)
/// \param foundEntities[out] vector of non-const EntityItem*
/// \param foundEntities[out] vector of non-EntityItemPointer
/// \remark Side effect: any initial contents in entities will be lost
void findEntities(const AABox& box, QVector<EntityItem*>& foundEntities);
void findEntities(const AABox& box, QVector<EntityItemPointer>& foundEntities);
void addNewlyCreatedHook(NewlyCreatedEntityHook* hook);
void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook);
@ -138,10 +138,10 @@ public:
EntityItemFBXService* getFBXService() const { return _fbxService; }
void setFBXService(EntityItemFBXService* service) { _fbxService = service; }
const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem) {
const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) {
return _fbxService ? _fbxService->getGeometryForEntity(entityItem) : NULL;
}
const Model* getModelForEntityItem(const EntityItem* entityItem) {
const Model* getModelForEntityItem(EntityItemPointer entityItem) {
return _fbxService ? _fbxService->getModelForEntityItem(entityItem) : NULL;
}
@ -153,7 +153,7 @@ public:
QVector<EntityItemID> sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z);
void entityChanged(EntityItem* entity);
void entityChanged(EntityItemPointer entity);
void emitEntityScriptChanging(const EntityItemID& entityItemID);
@ -171,13 +171,12 @@ signals:
void deletingEntity(const EntityItemID& entityID);
void addingEntity(const EntityItemID& entityID);
void entityScriptChanging(const EntityItemID& entityItemID);
void changingEntityID(const EntityItemID& oldEntityID, const EntityItemID& newEntityID);
void clearingEntities();
private:
void processRemovedEntities(const DeleteEntityOperator& theOperator);
bool updateEntityWithElement(EntityItem* entity, const EntityItemProperties& properties,
bool updateEntityWithElement(EntityItemPointer entity, const EntityItemProperties& properties,
EntityTreeElement* containingElement,
const SharedNodePointer& senderNode = SharedNodePointer(nullptr));
static bool findNearPointOperation(OctreeElement* element, void* extraData);

View file

@ -39,7 +39,7 @@ OctreeElement* EntityTreeElement::createNewElement(unsigned char* octalCode) {
void EntityTreeElement::init(unsigned char* octalCode) {
OctreeElement::init(octalCode);
_entityItems = new QList<EntityItem*>;
_entityItems = new EntityItems;
_octreeMemoryUsage += sizeof(EntityTreeElement);
}
@ -85,7 +85,7 @@ void EntityTreeElement::initializeExtraEncodeData(EncodeBitstreamParams& params)
}
}
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
EntityItemPointer entity = (*_entityItems)[i];
entityTreeElementExtraEncodeData->entities.insert(entity->getEntityItemID(), entity->getEntityProperties(params));
}
@ -263,7 +263,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
}
}
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
EntityItemPointer entity = (*_entityItems)[i];
entityTreeElementExtraEncodeData->entities.insert(entity->getEntityItemID(), entity->getEntityProperties(params));
}
}
@ -284,7 +284,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
// need to handle the case where our sibling elements need encoding but we don't.
if (!entityTreeElementExtraEncodeData->elementCompleted) {
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
EntityItemPointer entity = (*_entityItems)[i];
bool includeThisEntity = true;
if (!params.forceSendScene && entity->getLastChangedOnServer() < params.lastViewFrustumSent) {
@ -320,7 +320,7 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
if (successAppendEntityCount) {
foreach (uint16_t i, indexesOfEntitiesToInclude) {
EntityItem* entity = (*_entityItems)[i];
EntityItemPointer entity = (*_entityItems)[i];
LevelDetails entityLevel = packetData->startLevel();
OctreeElement::AppendState appendEntityState = entity->appendEntityData(packetData,
params, entityTreeElementExtraEncodeData);
@ -408,11 +408,11 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
return appendElementState;
}
bool EntityTreeElement::containsEntityBounds(const EntityItem* entity) const {
bool EntityTreeElement::containsEntityBounds(EntityItemPointer entity) const {
return containsBounds(entity->getMaximumAACube());
}
bool EntityTreeElement::bestFitEntityBounds(const EntityItem* entity) const {
bool EntityTreeElement::bestFitEntityBounds(EntityItemPointer entity) const {
return bestFitBounds(entity->getMaximumAACube());
}
@ -476,14 +476,14 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
// only called if we do intersect our bounding cube, but find if we actually intersect with entities...
int entityNumber = 0;
QList<EntityItem*>::iterator entityItr = _entityItems->begin();
QList<EntityItem*>::const_iterator entityEnd = _entityItems->end();
EntityItems::iterator entityItr = _entityItems->begin();
EntityItems::const_iterator entityEnd = _entityItems->end();
bool somethingIntersected = false;
//float bestEntityDistance = distance;
while(entityItr != entityEnd) {
EntityItem* entity = (*entityItr);
EntityItemPointer entity = (*entityItr);
AABox entityBox = entity->getAABox();
float localDistance;
@ -519,7 +519,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
if (localDistance < distance) {
distance = localDistance;
face = localFace;
*intersectedObject = (void*)entity;
*intersectedObject = (void*)entity.get();
somethingIntersected = true;
}
}
@ -528,7 +528,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
if (localDistance < distance) {
distance = localDistance;
face = localFace;
*intersectedObject = (void*)entity;
*intersectedObject = (void*)entity.get();
somethingIntersected = true;
}
}
@ -545,10 +545,10 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
// TODO: change this to use better bounding shape for entity than sphere
bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const {
QList<EntityItem*>::iterator entityItr = _entityItems->begin();
QList<EntityItem*>::const_iterator entityEnd = _entityItems->end();
EntityItems::iterator entityItr = _entityItems->begin();
EntityItems::const_iterator entityEnd = _entityItems->end();
while(entityItr != entityEnd) {
EntityItem* entity = (*entityItr);
EntityItemPointer entity = (*entityItr);
glm::vec3 entityCenter = entity->getPosition();
float entityRadius = entity->getRadius();
@ -559,7 +559,9 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
if (findSphereSpherePenetration(center, radius, entityCenter, entityRadius, penetration)) {
// return true on first valid entity penetration
*penetratedObject = (void*)(entity);
*penetratedObject = (void*)(entity.get());
return true;
}
++entityItr;
@ -567,8 +569,8 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad
return false;
}
const EntityItem* EntityTreeElement::getClosestEntity(glm::vec3 position) const {
const EntityItem* closestEntity = NULL;
EntityItemPointer EntityTreeElement::getClosestEntity(glm::vec3 position) const {
EntityItemPointer closestEntity = NULL;
float closestEntityDistance = FLT_MAX;
uint16_t numberOfEntities = _entityItems->size();
for (uint16_t i = 0; i < numberOfEntities; i++) {
@ -581,10 +583,10 @@ const EntityItem* EntityTreeElement::getClosestEntity(glm::vec3 position) const
}
// TODO: change this to use better bounding shape for entity than sphere
void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searchRadius, QVector<const EntityItem*>& foundEntities) const {
void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searchRadius, QVector<EntityItemPointer>& foundEntities) const {
uint16_t numberOfEntities = _entityItems->size();
for (uint16_t i = 0; i < numberOfEntities; i++) {
const EntityItem* entity = (*_entityItems)[i];
EntityItemPointer entity = (*_entityItems)[i];
float distance = glm::length(entity->getPosition() - searchPosition);
if (distance < searchRadius + entity->getRadius()) {
foundEntities.push_back(entity);
@ -593,12 +595,12 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc
}
// TODO: change this to use better bounding shape for entity than sphere
void EntityTreeElement::getEntities(const AACube& box, QVector<EntityItem*>& foundEntities) {
QList<EntityItem*>::iterator entityItr = _entityItems->begin();
QList<EntityItem*>::iterator entityEnd = _entityItems->end();
void EntityTreeElement::getEntities(const AACube& box, QVector<EntityItemPointer>& foundEntities) {
EntityItems::iterator entityItr = _entityItems->begin();
EntityItems::iterator entityEnd = _entityItems->end();
AACube entityCube;
while(entityItr != entityEnd) {
EntityItem* entity = (*entityItr);
EntityItemPointer entity = (*entityItr);
float radius = entity->getRadius();
// NOTE: we actually do cube-cube collision queries here, which is sloppy but good enough for now
// TODO: decide whether to replace entityCube-cube query with sphere-cube (requires a square root
@ -611,8 +613,8 @@ void EntityTreeElement::getEntities(const AACube& box, QVector<EntityItem*>& fou
}
}
const EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) const {
const EntityItem* foundEntity = NULL;
EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) const {
EntityItemPointer foundEntity = NULL;
uint16_t numberOfEntities = _entityItems->size();
for (uint16_t i = 0; i < numberOfEntities; i++) {
if ((*_entityItems)[i]->getEntityItemID() == id) {
@ -623,8 +625,8 @@ const EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemI
return foundEntity;
}
EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) {
EntityItem* foundEntity = NULL;
EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) {
EntityItemPointer foundEntity = NULL;
uint16_t numberOfEntities = _entityItems->size();
for (uint16_t i = 0; i < numberOfEntities; i++) {
if ((*_entityItems)[i]->getEntityItemID() == id) {
@ -638,9 +640,13 @@ EntityItem* EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id)
void EntityTreeElement::cleanupEntities() {
uint16_t numberOfEntities = _entityItems->size();
for (uint16_t i = 0; i < numberOfEntities; i++) {
EntityItem* entity = (*_entityItems)[i];
EntityItemPointer entity = (*_entityItems)[i];
entity->_element = NULL;
delete entity;
// NOTE: We explicitly don't delete the EntityItem here because since we only
// access it by smart pointers, when we remove it from the _entityItems
// we know that it will be deleted.
//delete entity;
}
_entityItems->clear();
}
@ -659,7 +665,7 @@ bool EntityTreeElement::removeEntityWithEntityItemID(const EntityItemID& id) {
return foundEntity;
}
bool EntityTreeElement::removeEntityItem(EntityItem* entity) {
bool EntityTreeElement::removeEntityItem(EntityItemPointer entity) {
int numEntries = _entityItems->removeAll(entity);
if (numEntries > 0) {
assert(entity->_element == this);
@ -706,7 +712,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
for (uint16_t i = 0; i < numberOfEntities; i++) {
int bytesForThisEntity = 0;
EntityItemID entityItemID;
EntityItem* entityItem = NULL;
EntityItemPointer entityItem = NULL;
// Old model files don't have UUIDs in them. So we don't want to try to read those IDs from the stream.
// Since this can only happen on loading an old file, we can safely treat these as new entity cases,
@ -771,7 +777,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
return bytesRead;
}
void EntityTreeElement::addEntityItem(EntityItem* entity) {
void EntityTreeElement::addEntityItem(EntityItemPointer entity) {
assert(entity);
assert(entity->_element == NULL);
_entityItems->push_back(entity);
@ -809,7 +815,7 @@ bool EntityTreeElement::pruneChildren() {
void EntityTreeElement::expandExtentsToContents(Extents& extents) {
if (_entityItems->size()) {
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
EntityItemPointer entity = (*_entityItems)[i];
extents.add(entity->getAABox());
}
}
@ -825,7 +831,7 @@ void EntityTreeElement::debugDump() {
qCDebug(entities) << " has entities:" << _entityItems->size();
qCDebug(entities) << "--------------------------------------------------";
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
EntityItemPointer entity = (*_entityItems)[i];
entity->debugDump();
}
qCDebug(entities) << "--------------------------------------------------";

View file

@ -12,6 +12,8 @@
#ifndef hifi_EntityTreeElement_h
#define hifi_EntityTreeElement_h
#include <memory>
#include <OctreeElement.h>
#include <QList>
@ -19,6 +21,8 @@
#include "EntityItem.h"
#include "EntityTree.h"
typedef QVector<EntityItemPointer> EntityItems;
class EntityTree;
class EntityTreeElement;
@ -30,7 +34,7 @@ public:
_movingItems(0)
{ }
QList<EntityItem*> _movingEntities;
QList<EntityItemPointer> _movingEntities;
int _totalElements;
int _totalItems;
int _movingItems;
@ -142,40 +146,41 @@ public:
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const;
const QList<EntityItem*>& getEntities() const { return *_entityItems; }
QList<EntityItem*>& getEntities() { return *_entityItems; }
const EntityItems& getEntities() const { return *_entityItems; }
EntityItems& getEntities() { return *_entityItems; }
bool hasEntities() const { return _entityItems ? _entityItems->size() > 0 : false; }
void setTree(EntityTree* tree) { _myTree = tree; }
bool updateEntity(const EntityItem& entity);
void addEntityItem(EntityItem* entity);
void addEntityItem(EntityItemPointer entity);
const EntityItem* getClosestEntity(glm::vec3 position) const;
EntityItemPointer getClosestEntity(glm::vec3 position) const;
/// finds all entities that touch a sphere
/// \param position the center of the query sphere
/// \param radius the radius of the query sphere
/// \param entities[out] vector of const EntityItem*
void getEntities(const glm::vec3& position, float radius, QVector<const EntityItem*>& foundEntities) const;
/// \param entities[out] vector of const EntityItemPointer
void getEntities(const glm::vec3& position, float radius, QVector<EntityItemPointer>& foundEntities) const;
/// finds all entities that touch a box
/// \param box the query box
/// \param entities[out] vector of non-const EntityItem*
void getEntities(const AACube& box, QVector<EntityItem*>& foundEntities);
/// \param entities[out] vector of non-const EntityItemPointer
void getEntities(const AACube& box, QVector<EntityItemPointer>& foundEntities);
const EntityItem* getEntityWithID(uint32_t id) const;
const EntityItem* getEntityWithEntityItemID(const EntityItemID& id) const;
void getEntitiesInside(const AACube& box, QVector<EntityItem*>& foundEntities);
EntityItemPointer getEntityWithID(uint32_t id) const;
EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const;
void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities);
EntityItem* getEntityWithEntityItemID(const EntityItemID& id);
EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id);
void cleanupEntities(); /// called by EntityTree on cleanup this will free all entities
bool removeEntityWithEntityItemID(const EntityItemID& id);
bool removeEntityItem(EntityItem* entity);
bool removeEntityItem(EntityItemPointer entity);
bool containsEntityBounds(const EntityItem* entity) const;
bool bestFitEntityBounds(const EntityItem* entity) const;
bool containsEntityBounds(EntityItemPointer entity) const;
bool bestFitEntityBounds(EntityItemPointer entity) const;
bool containsBounds(const EntityItemProperties& properties) const; // NOTE: property units in meters
bool bestFitBounds(const EntityItemProperties& properties) const; // NOTE: property units in meters
@ -198,7 +203,7 @@ public:
protected:
virtual void init(unsigned char * octalCode);
EntityTree* _myTree;
QList<EntityItem*>* _entityItems;
EntityItems* _entityItems;
};
#endif // hifi_EntityTreeElement_h

View file

@ -76,9 +76,9 @@ bool EntityTypes::registerEntityType(EntityType entityType, const char* name, En
return false;
}
EntityItem* EntityTypes::constructEntityItem(EntityType entityType, const EntityItemID& entityID,
EntityItemPointer EntityTypes::constructEntityItem(EntityType entityType, const EntityItemID& entityID,
const EntityItemProperties& properties) {
EntityItem* newEntityItem = NULL;
EntityItemPointer newEntityItem = NULL;
EntityTypeFactory factory = NULL;
if (entityType >= 0 && entityType <= LAST) {
factory = _factories[entityType];
@ -91,7 +91,7 @@ EntityItem* EntityTypes::constructEntityItem(EntityType entityType, const Entity
return newEntityItem;
}
EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int bytesToRead,
EntityItemPointer EntityTypes::constructEntityItem(const unsigned char* data, int bytesToRead,
ReadBitstreamToTreeParams& args) {
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {

View file

@ -20,11 +20,17 @@
#include <OctreeRenderer.h> // for RenderArgs
class EntityItem;
typedef std::shared_ptr<EntityItem> EntityItemPointer;
inline uint qHash(const EntityItemPointer& a, uint seed) {
return qHash(a.get(), seed);
}
class EntityItemID;
class EntityItemProperties;
class ReadBitstreamToTreeParams;
typedef EntityItem* (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties);
typedef EntityItemPointer (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties);
class EntityTypes {
public:
@ -45,8 +51,8 @@ public:
static const QString& getEntityTypeName(EntityType entityType);
static EntityTypes::EntityType getEntityTypeFromName(const QString& name);
static bool registerEntityType(EntityType entityType, const char* name, EntityTypeFactory factoryMethod);
static EntityItem* constructEntityItem(EntityType entityType, const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItem* constructEntityItem(const unsigned char* data, int bytesToRead, ReadBitstreamToTreeParams& args);
static EntityItemPointer constructEntityItem(EntityType entityType, const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer constructEntityItem(const unsigned char* data, int bytesToRead, ReadBitstreamToTreeParams& args);
private:
static QMap<EntityType, QString> _typeToNameMap;
@ -59,7 +65,7 @@ private:
/// Macro for registering entity types. Make sure to add an element to the EntityType enum with your name, and your class should be
/// named NameEntityItem and must of a static method called factory that takes an EnityItemID, and EntityItemProperties and return a newly
/// constructed (heap allocated) instance of your type. e.g. The following prototype:
// static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
// static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
#define REGISTER_ENTITY_TYPE(x) static bool x##Registration = \
EntityTypes::registerEntityType(EntityTypes::x, #x, x##EntityItem::factory);
@ -67,7 +73,7 @@ private:
/// an element to the EntityType enum with your name. But unlike REGISTER_ENTITY_TYPE, your class can be named anything
/// so long as you provide a static method passed to the macro, that takes an EnityItemID, and EntityItemProperties and
/// returns a newly constructed (heap allocated) instance of your type. e.g. The following prototype:
// static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
// static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
#define REGISTER_ENTITY_TYPE_WITH_FACTORY(x,y) static bool x##Registration = \
EntityTypes::registerEntityType(EntityTypes::x, #x, y); \
if (!x##Registration) { \

View file

@ -22,8 +22,9 @@
bool LightEntityItem::_lightsArePickable = false;
EntityItem* LightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new LightEntityItem(entityID, properties);
EntityItemPointer LightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result { new LightEntityItem(entityID, properties) };
return result;
}
// our non-pure virtual subclass for now...

View file

@ -16,7 +16,7 @@
class LightEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);

View file

@ -20,8 +20,8 @@
#include "EntityTreeElement.h"
EntityItem* LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItem* result = new LineEntityItem(entityID, properties);
EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result { new LineEntityItem(entityID, properties) };
return result;
}

View file

@ -16,7 +16,7 @@
class LineEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
LineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);

View file

@ -28,8 +28,8 @@ const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false;
const float ModelEntityItem::DEFAULT_ANIMATION_FPS = 30.0f;
EntityItem* ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new ModelEntityItem(entityID, properties);
EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new ModelEntityItem(entityID, properties));
}
ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :

View file

@ -18,7 +18,7 @@
class ModelEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);

View file

@ -50,7 +50,7 @@ MovingEntitiesOperator::~MovingEntitiesOperator() {
}
void MovingEntitiesOperator::addEntityToMoveList(EntityItem* entity, const AACube& newCube) {
void MovingEntitiesOperator::addEntityToMoveList(EntityItemPointer entity, const AACube& newCube) {
EntityTreeElement* oldContainingElement = _tree->getContainingElement(entity->getEntityItemID());
AABox newCubeClamped = newCube.clamp(0.0f, (float)TREE_SCALE);

View file

@ -14,7 +14,7 @@
class EntityToMoveDetails {
public:
EntityItem* entity;
EntityItemPointer entity;
AACube oldCube; // meters
AACube newCube; // meters
AABox newCubeClamped; // meters
@ -37,7 +37,7 @@ public:
MovingEntitiesOperator(EntityTree* tree);
~MovingEntitiesOperator();
void addEntityToMoveList(EntityItem* entity, const AACube& newCube);
void addEntityToMoveList(EntityItemPointer entity, const AACube& newCube);
virtual bool preRecursion(OctreeElement* element);
virtual bool postRecursion(OctreeElement* element);
virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex);

View file

@ -55,8 +55,8 @@ const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f;
const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = "";
EntityItem* ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new ParticleEffectEntityItem(entityID, properties);
EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new ParticleEffectEntityItem(entityID, properties));
}
// our non-pure virtual subclass for now...
@ -490,19 +490,21 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
}
void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
_maxParticles = maxParticles;
if (_maxParticles != maxParticles) {
_maxParticles = maxParticles;
// TODO: try to do something smart here and preserve the state of existing particles.
// TODO: try to do something smart here and preserve the state of existing particles.
// resize vectors
_particleLifetimes.resize(_maxParticles);
_particlePositions.resize(_maxParticles);
_particleVelocities.resize(_maxParticles);
// resize vectors
_particleLifetimes.resize(_maxParticles);
_particlePositions.resize(_maxParticles);
_particleVelocities.resize(_maxParticles);
// effectivly clear all particles and start emitting new ones from scratch.
_particleHeadIndex = 0;
_particleTailIndex = 0;
_timeUntilNextEmit = 0.0f;
// effectivly clear all particles and start emitting new ones from scratch.
_particleHeadIndex = 0;
_particleTailIndex = 0;
_timeUntilNextEmit = 0.0f;
}
}
// because particles are in a ring buffer, this isn't trivial

View file

@ -17,7 +17,7 @@
class ParticleEffectEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual ~ParticleEffectEntityItem();

View file

@ -43,11 +43,11 @@ bool RecurseOctreeToMapOperator::postRecursion(OctreeElement* element) {
EntityItemProperties defaultProperties;
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
const QList<EntityItem*>& entities = entityTreeElement->getEntities();
const EntityItems& entities = entityTreeElement->getEntities();
QVariantList entitiesQList = qvariant_cast<QVariantList>(_map["Entities"]);
foreach (EntityItem* entityItem, entities) {
foreach (EntityItemPointer entityItem, entities) {
EntityItemProperties properties = entityItem->getProperties();
QScriptValue qScriptValues;
if (_skipDefaultValues) {

View file

@ -25,7 +25,7 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) {
SetOfEntities::iterator itemItr = _hasSimulationOwnerEntities.begin();
while (itemItr != _hasSimulationOwnerEntities.end()) {
EntityItem* entity = *itemItr;
EntityItemPointer entity = *itemItr;
if (entity->getSimulatorID().isNull()) {
itemItr = _hasSimulationOwnerEntities.erase(itemItr);
} else if (now - entity->getLastChangedOnServer() >= AUTO_REMOVE_SIMULATION_OWNER_USEC) {
@ -44,18 +44,18 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) {
}
}
void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) {
void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) {
EntitySimulation::addEntityInternal(entity);
if (!entity->getSimulatorID().isNull()) {
_hasSimulationOwnerEntities.insert(entity);
}
}
void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) {
void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) {
_hasSimulationOwnerEntities.remove(entity);
}
void SimpleEntitySimulation::changeEntityInternal(EntityItem* entity) {
void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
EntitySimulation::changeEntityInternal(entity);
if (!entity->getSimulatorID().isNull()) {
_hasSimulationOwnerEntities.insert(entity);

View file

@ -23,9 +23,9 @@ public:
protected:
virtual void updateEntitiesInternal(const quint64& now);
virtual void addEntityInternal(EntityItem* entity);
virtual void removeEntityInternal(EntityItem* entity);
virtual void changeEntityInternal(EntityItem* entity);
virtual void addEntityInternal(EntityItemPointer entity);
virtual void removeEntityInternal(EntityItemPointer entity);
virtual void changeEntityInternal(EntityItemPointer entity);
virtual void clearEntitiesInternal();
SetOfEntities _hasSimulationOwnerEntities;

View file

@ -23,8 +23,9 @@
#include "SphereEntityItem.h"
EntityItem* SphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new SphereEntityItem(entityID, properties);
EntityItemPointer SphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer result { new SphereEntityItem(entityID, properties) };
return result;
}
// our non-pure virtual subclass for now...

View file

@ -16,7 +16,7 @@
class SphereEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);

View file

@ -28,9 +28,8 @@ const float TextEntityItem::DEFAULT_LINE_HEIGHT = 0.1f;
const xColor TextEntityItem::DEFAULT_TEXT_COLOR = { 255, 255, 255 };
const xColor TextEntityItem::DEFAULT_BACKGROUND_COLOR = { 0, 0, 0};
EntityItem* TextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItem* result = new TextEntityItem(entityID, properties);
return result;
EntityItemPointer TextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new TextEntityItem(entityID, properties));
}
TextEntityItem::TextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :

View file

@ -16,7 +16,7 @@
class TextEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
TextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);

View file

@ -18,7 +18,7 @@
UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
EntityTreeElement* containingElement,
EntityItem* existingEntity,
EntityItemPointer existingEntity,
const EntityItemProperties& properties) :
_tree(tree),
_existingEntity(existingEntity),

View file

@ -15,7 +15,7 @@
class UpdateEntityOperator : public RecurseOctreeOperator {
public:
UpdateEntityOperator(EntityTree* tree, EntityTreeElement* containingElement,
EntityItem* existingEntity, const EntityItemProperties& properties);
EntityItemPointer existingEntity, const EntityItemProperties& properties);
~UpdateEntityOperator();
virtual bool preRecursion(OctreeElement* element);
@ -23,7 +23,7 @@ public:
virtual OctreeElement* possiblyCreateChildAt(OctreeElement* element, int childIndex);
private:
EntityTree* _tree;
EntityItem* _existingEntity;
EntityItemPointer _existingEntity;
EntityTreeElement* _containingElement;
AACube _containingElementCube; // we temporarily store our cube here in case we need to delete the containing element
EntityItemProperties _properties;

View file

@ -22,9 +22,8 @@
const QString WebEntityItem::DEFAULT_SOURCE_URL("http://www.google.com");
EntityItem* WebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItem* result = new WebEntityItem(entityID, properties);
return result;
EntityItemPointer WebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new WebEntityItem(entityID, properties));
}
WebEntityItem::WebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :

View file

@ -15,7 +15,7 @@ class WebEntityItem : public EntityItem {
public:
static const QString DEFAULT_SOURCE_URL;
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
WebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);

View file

@ -29,9 +29,8 @@ const glm::vec3 ZoneEntityItem::DEFAULT_KEYLIGHT_DIRECTION = { 0.0f, -1.0f, 0.0f
const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX;
const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = "";
EntityItem* ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItem* result = new ZoneEntityItem(entityID, properties);
return result;
EntityItemPointer ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new ZoneEntityItem(entityID, properties));
}
ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :

View file

@ -19,7 +19,7 @@
class ZoneEntityItem : public EntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);

View file

@ -32,12 +32,6 @@ Assignment::Type Assignment::typeForNodeType(NodeType_t nodeType) {
}
}
#ifdef WIN32
//warning C4351: new behavior: elements of array 'Assignment::_payload' will be default initialized
// We're disabling this warning because the new behavior which is to initialize the array with 0 is acceptable to us.
#pragma warning(disable:4351)
#endif
Assignment::Assignment() :
_uuid(),
_command(Assignment::RequestCommand),

View file

@ -22,7 +22,7 @@ static const float ACCELERATION_EQUIVALENT_EPSILON_RATIO = 0.1f;
static const quint8 STEPS_TO_DECIDE_BALLISTIC = 4;
EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItem* entity) :
EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) :
ObjectMotionState(shape),
_entity(entity),
_sentActive(false),
@ -132,7 +132,6 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
uint32_t thisStep = ObjectMotionState::getWorldSimulationStep();
float dt = (thisStep - _lastKinematicStep) * PHYSICS_ENGINE_FIXED_SUBSTEP;
_entity->simulateKinematicMotion(dt);
_entity->setLastSimulated(usecTimestampNow());
// bypass const-ness so we can remember the step
const_cast<EntityMotionState*>(this)->_lastKinematicStep = thisStep;
@ -401,13 +400,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
properties.setAcceleration(_serverAcceleration);
properties.setAngularVelocity(_serverAngularVelocity);
// we only update lastEdited when we're sending new physics data
quint64 lastSimulated = _entity->getLastSimulated();
_entity->setLastEdited(lastSimulated);
properties.setLastEdited(lastSimulated);
// set the LastEdited of the properties but NOT the entity itself
quint64 now = usecTimestampNow();
properties.setLastEdited(now);
#ifdef WANT_DEBUG
quint64 now = usecTimestampNow();
quint64 lastSimulated = _entity->getLastSimulated();
qCDebug(physics) << "EntityMotionState::sendUpdate()";
qCDebug(physics) << " EntityItemId:" << _entity->getEntityItemID()
<< "---------------------------------------------";

View file

@ -25,7 +25,7 @@ class EntityItem;
class EntityMotionState : public ObjectMotionState {
public:
EntityMotionState(btCollisionShape* shape, EntityItem* item);
EntityMotionState(btCollisionShape* shape, EntityItemPointer item);
virtual ~EntityMotionState();
void updateServerPhysicsVariables(uint32_t flags);
@ -70,7 +70,7 @@ public:
virtual QUuid getSimulatorID() const;
virtual void bump();
EntityItem* getEntity() const { return _entity; }
EntityItemPointer getEntity() const { return _entity; }
void resetMeasuredBodyAcceleration();
void measureBodyAcceleration();
@ -84,7 +84,7 @@ protected:
virtual void clearObjectBackPointer();
virtual void setMotionType(MotionType motionType);
EntityItem* _entity;
EntityItemPointer _entity;
bool _sentActive; // true if body was active when we sent last update
int _numNonMovingUpdates; // RELIABLE_SEND_HACK for "not so reliable" resends of packets for non-moving objects

View file

@ -1,150 +0,0 @@
//
// MeshInfo.cpp
// libraries/physics/src
//
// Created by Virendra Singh 2015.02.28
// 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 "MeshInfo.h"
#include <iostream>
using namespace meshinfo;
//class to compute volume, mass, center of mass, and inertia tensor of a mesh.
//origin is the default reference point for generating the tetrahedron from each triangle of the mesh.
MeshInfo::MeshInfo(vector<Vertex> *vertices, vector<int> *triangles) :\
_vertices(vertices),
_centerOfMass(Vertex(0.0, 0.0, 0.0)),
_triangles(triangles)
{
}
MeshInfo::~MeshInfo(){
_vertices = NULL;
_triangles = NULL;
}
inline float MeshInfo::getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const{
glm::mat4 tet = { glm::vec4(p1.x, p2.x, p3.x, p4.x), glm::vec4(p1.y, p2.y, p3.y, p4.y), glm::vec4(p1.z, p2.z, p3.z, p4.z),
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f) };
return glm::determinant(tet) / 6.0f;
}
Vertex MeshInfo::getMeshCentroid() const{
return _centerOfMass;
}
vector<float> MeshInfo::computeMassProperties(){
vector<float> volumeAndInertia = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
Vertex origin(0.0, 0.0, 0.0);
glm::mat3 identity;
float meshVolume = 0.0f;
glm::mat3 globalInertiaTensors(0.0);
for (unsigned int i = 0; i < _triangles->size(); i += 3){
Vertex p1 = _vertices->at(_triangles->at(i));
Vertex p2 = _vertices->at(_triangles->at(i + 1));
Vertex p3 = _vertices->at(_triangles->at(i + 2));
float volume = getVolume(p1, p2, p3, origin);
Vertex com = 0.25f * (p1 + p2 + p3);
meshVolume += volume;
_centerOfMass += com * volume;
//centroid is used for calculating inertia tensor relative to center of mass.
// translate the tetrahedron to its center of mass using P = P - centroid
Vertex p0 = origin - com;
p1 = p1 - com;
p2 = p2 - com;
p3 = p3 - com;
//Calculate inertia tensor based on Tonon's Formulae given in the paper mentioned below.
//http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf
//Explicit exact formulas for the 3-D tetrahedron inertia tensor in terms of its vertex coordinates - F.Tonon
float i11 = (volume * 0.1f) * (
p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y +
p1.y*p1.y + p1.y*p2.y + p1.y*p3.y +
p2.y*p2.y + p2.y*p3.y +
p3.y*p3.y +
p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z +
p1.z*p1.z + p1.z*p2.z + p1.z*p3.z +
p2.z*p2.z + p2.z*p3.z +
p3.z*p3.z);
float i22 = (volume * 0.1f) * (
p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x +
p1.x*p1.x + p1.x*p2.x + p1.x*p3.x +
p2.x*p2.x + p2.x*p3.x +
p3.x*p3.x +
p0.z*p0.z + p0.z*p1.z + p0.z*p2.z + p0.z*p3.z +
p1.z*p1.z + p1.z*p2.z + p1.z*p3.z +
p2.z*p2.z + p2.z*p3.z +
p3.z*p3.z);
float i33 = (volume * 0.1f) * (
p0.x*p0.x + p0.x*p1.x + p0.x*p2.x + p0.x*p3.x +
p1.x*p1.x + p1.x*p2.x + p1.x*p3.x +
p2.x*p2.x + p2.x*p3.x +
p3.x*p3.x +
p0.y*p0.y + p0.y*p1.y + p0.y*p2.y + p0.y*p3.y +
p1.y*p1.y + p1.y*p2.y + p1.y*p3.y +
p2.y*p2.y + p2.y*p3.y +
p3.y*p3.y);
float i23 = -(volume * 0.05f) * (2.0f * (p0.y*p0.z + p1.y*p1.z + p2.y*p2.z + p3.y*p3.z) +
p0.y*p1.z + p0.y*p2.z + p0.y*p3.z +
p1.y*p0.z + p1.y*p2.z + p1.y*p3.z +
p2.y*p0.z + p2.y*p1.z + p2.y*p3.z +
p3.y*p0.z + p3.y*p1.z + p3.y*p2.z);
float i21 = -(volume * 0.05f) * (2.0f * (p0.x*p0.z + p1.x*p1.z + p2.x*p2.z + p3.x*p3.z) +
p0.x*p1.z + p0.x*p2.z + p0.x*p3.z +
p1.x*p0.z + p1.x*p2.z + p1.x*p3.z +
p2.x*p0.z + p2.x*p1.z + p2.x*p3.z +
p3.x*p0.z + p3.x*p1.z + p3.x*p2.z);
float i31 = -(volume * 0.05f) * (2.0f * (p0.x*p0.y + p1.x*p1.y + p2.x*p2.y + p3.x*p3.y) +
p0.x*p1.y + p0.x*p2.y + p0.x*p3.y +
p1.x*p0.y + p1.x*p2.y + p1.x*p3.y +
p2.x*p0.y + p2.x*p1.y + p2.x*p3.y +
p3.x*p0.y + p3.x*p1.y + p3.x*p2.y);
//3x3 of local inertia tensors of each tetrahedron. Inertia tensors are the diagonal elements
// | I11 -I12 -I13 |
// I = | -I21 I22 -I23 |
// | -I31 -I32 I33 |
glm::mat3 localInertiaTensors = { Vertex(i11, i21, i31), Vertex(i21, i22, i23),
Vertex(i31, i23, i33) };
//Translate the inertia tensors from center of mass to origin
//Parallel axis theorem J = I * m[(R.R)*Identity - RxR] where x is outer cross product
globalInertiaTensors += localInertiaTensors + volume * ((glm::dot(com, com) * identity) -
glm::outerProduct(com, com));
}
//Translate accumulated center of mass from each tetrahedron to mesh's center of mass using parallel axis theorem
if (meshVolume == 0){
return volumeAndInertia;
}
_centerOfMass = (_centerOfMass / meshVolume);
//Translate the inertia tensors from origin to mesh's center of mass.
globalInertiaTensors = globalInertiaTensors - meshVolume * ((glm::dot(_centerOfMass, _centerOfMass) *
identity) - glm::outerProduct(_centerOfMass, _centerOfMass));
volumeAndInertia[0] = meshVolume;
volumeAndInertia[1] = globalInertiaTensors[0][0]; //i11
volumeAndInertia[2] = globalInertiaTensors[1][1]; //i22
volumeAndInertia[3] = globalInertiaTensors[2][2]; //i33
volumeAndInertia[4] = -globalInertiaTensors[2][1]; //i23 or i32
volumeAndInertia[5] = -globalInertiaTensors[1][0]; //i21 or i12
volumeAndInertia[6] = -globalInertiaTensors[2][0]; //i13 or i31
return volumeAndInertia;
}

View file

@ -1,33 +0,0 @@
//
// MeshInfo.h
// libraries/physics/src
//
// Created by Virendra Singh 2015.02.28
// 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
//
#ifndef hifi_MeshInfo_h
#define hifi_MeshInfo_h
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtx/norm.hpp>
using namespace std;
namespace meshinfo{
typedef glm::vec3 Vertex;
class MeshInfo{
private:
inline float getVolume(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const;
vector<float> computeVolumeAndInertia(const Vertex p1, const Vertex p2, const Vertex p3, const Vertex p4) const;
public:
vector<Vertex> *_vertices;
Vertex _centerOfMass;
vector<int> *_triangles;
MeshInfo(vector<Vertex> *vertices, vector<int> *triangles);
~MeshInfo();
Vertex getMeshCentroid() const;
vector<float> computeMassProperties();
};
}
#endif // hifi_MeshInfo_h

View file

@ -0,0 +1,321 @@
//
// MeshMassProperties.cpp
// libraries/physics/src
//
// Created by Andrew Meadows 2015.05.25
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <assert.h>
#include <stdint.h>
#include "MeshMassProperties.h"
// this method is included for unit test verification
void computeBoxInertia(btScalar mass, const btVector3& diagonal, btMatrix3x3& inertia) {
// formula for box inertia tensor:
//
// | y^2 + z^2 0 0 |
// | |
// inertia = M/12 * | 0 z^2 + x^2 0 |
// | |
// | 0 0 x^2 + y^2 |
//
mass = mass / btScalar(12.0f);
btScalar x = diagonal[0];
x = mass * x * x;
btScalar y = diagonal[1];
y = mass * y * y;
btScalar z = diagonal[2];
z = mass * z * z;
inertia.setIdentity();
inertia[0][0] = y + z;
inertia[1][1] = z + x;
inertia[2][2] = x + y;
}
void computeTetrahedronInertia(btScalar mass, btVector3* points, btMatrix3x3& inertia) {
// Computes the inertia tensor of a tetrahedron about its center of mass.
// The tetrahedron is defined by array of four points in its center of mass frame.
//
// The analytic formulas were obtained from Tonon's paper:
// http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf
// http://thescipub.com/PDF/jmssp.2005.8.11.pdf
//
// The inertia tensor has the following form:
//
// | a f e |
// | |
// inertia = | f b d |
// | |
// | e d c |
const btVector3& p0 = points[0];
const btVector3& p1 = points[1];
const btVector3& p2 = points[2];
const btVector3& p3 = points[3];
for (uint32_t i = 0; i < 3; ++i ) {
uint32_t j = (i + 1) % 3;
uint32_t k = (j + 1) % 3;
// compute diagonal
inertia[i][i] = mass * btScalar(0.1f) *
( p0[j] * (p0[j] + p1[j] + p2[j] + p3[j])
+ p1[j] * (p1[j] + p2[j] + p3[j])
+ p2[j] * (p2[j] + p3[j])
+ p3[j] * p3[j]
+ p0[k] * (p0[k] + p1[k] + p2[k] + p3[k])
+ p1[k] * (p1[k] + p2[k] + p3[k])
+ p2[k] * (p2[k] + p3[k])
+ p3[k] * p3[k] );
// compute off-diagonals
inertia[j][k] = inertia[k][j] = - mass * btScalar(0.05f) *
( btScalar(2.0f) * ( p0[j] * p0[k] + p1[j] * p1[k] + p2[j] * p2[k] + p3[j] * p3[k] )
+ p0[j] * (p1[k] + p2[k] + p3[k])
+ p1[j] * (p0[k] + p2[k] + p3[k])
+ p2[j] * (p0[k] + p1[k] + p3[k])
+ p3[j] * (p0[k] + p1[k] + p2[k]) );
}
}
// helper function
void computePointInertia(const btVector3& point, btScalar mass, btMatrix3x3& inertia) {
btScalar distanceSquared = point.length2();
if (distanceSquared > 0.0f) {
for (uint32_t i = 0; i < 3; ++i) {
btScalar pointi = point[i];
inertia[i][i] = mass * (distanceSquared - (pointi * pointi));
for (uint32_t j = i + 1; j < 3; ++j) {
btScalar offDiagonal = - mass * pointi * point[j];
inertia[i][j] = offDiagonal;
inertia[j][i] = offDiagonal;
}
}
}
}
// this method is included for unit test verification
void computeTetrahedronInertiaByBruteForce(btVector3* points, btMatrix3x3& inertia) {
// Computes the approximate inertia tensor of a tetrahedron (about frame's origin)
// by integration over the "point" masses. This is numerically expensive so it may
// take a while to complete.
VectorOfIndices triangles = {
0, 2, 1,
0, 3, 2,
0, 1, 3,
1, 2, 3 };
for (int i = 0; i < 3; ++i) {
inertia[i].setZero();
}
// compute normals
btVector3 center = btScalar(0.25f) * (points[0] + points[1] + points[2] + points[3]);
btVector3 normals[4];
btVector3 pointsOnPlane[4];
for (int i = 0; i < 4; ++i) {
int t = 3 * i;
btVector3& p0 = points[triangles[t]];
btVector3& p1 = points[triangles[t + 1]];
btVector3& p2 = points[triangles[t + 2]];
normals[i] = ((p1 - p0).cross(p2 - p1)).normalized();
// make sure normal points away from center
if (normals[i].dot(p0 - center) < btScalar(0.0f)) {
normals[i] *= btScalar(-1.0f);
}
pointsOnPlane[i] = p0;
}
// compute bounds of integration
btVector3 boxMax = points[0];
btVector3 boxMin = points[0];
for (int i = 1; i < 4; ++i) {
for(int j = 0; j < 3; ++j) {
if (points[i][j] > boxMax[j]) {
boxMax[j] = points[i][j];
}
if (points[i][j] < boxMin[j]) {
boxMin[j] = points[i][j];
}
}
}
// compute step size
btVector3 diagonal = boxMax - boxMin;
btScalar maxDimension = diagonal[0];
if (diagonal[1] > maxDimension) {
maxDimension = diagonal[1];
}
if (diagonal[2] > maxDimension) {
maxDimension = diagonal[2];
}
btScalar resolutionOfIntegration = btScalar(400.0f);
btScalar delta = maxDimension / resolutionOfIntegration;
btScalar deltaVolume = delta * delta * delta;
// integrate over three dimensions
btMatrix3x3 deltaInertia;
btScalar XX = boxMax[0];
btScalar YY = boxMax[1];
btScalar ZZ = boxMax[2];
btScalar x = boxMin[0];
while(x < XX) {
btScalar y = boxMin[1];
while (y < YY) {
btScalar z = boxMin[2];
while (z < ZZ) {
btVector3 p(x, y, z);
// the point is inside the shape if it is behind all face planes
bool pointInside = true;
for (int i = 0; i < 4; ++i) {
if ((p - pointsOnPlane[i]).dot(normals[i]) > btScalar(0.0f)) {
pointInside = false;
break;
}
}
if (pointInside) {
// this point contributes to the total
computePointInertia(p, deltaVolume, deltaInertia);
inertia += deltaInertia;
}
z += delta;
}
y += delta;
}
x += delta;
}
}
btScalar computeTetrahedronVolume(btVector3* points) {
// Assumes triangle {1, 2, 3} is wound according to the right-hand-rule.
// NOTE: volume may be negative, in which case the tetrahedron contributes negatively to totals
// volume = (face_area * face_normal).dot(face_to_far_point) / 3.0
// (face_area * face_normal) = side0.cross(side1) / 2.0
return ((points[2] - points[1]).cross(points[3] - points[2])).dot(points[3] - points[0]) / btScalar(6.0f);
}
void applyParallelAxisTheorem(btMatrix3x3& inertia, const btVector3& shift, btScalar mass) {
// Parallel Axis Theorem says:
//
// Ishifted = Icm + M * [ (R*R)E - R(x)R ]
//
// where R*R = inside product
// R(x)R = outside product
// E = identity matrix
btScalar distanceSquared = shift.length2();
if (distanceSquared > btScalar(0.0f)) {
for (uint32_t i = 0; i < 3; ++i) {
btScalar shifti = shift[i];
inertia[i][i] += mass * (distanceSquared - (shifti * shifti));
for (uint32_t j = i + 1; j < 3; ++j) {
btScalar offDiagonal = mass * shifti * shift[j];
inertia[i][j] -= offDiagonal;
inertia[j][i] -= offDiagonal;
}
}
}
}
// helper function
void applyInverseParallelAxisTheorem(btMatrix3x3& inertia, const btVector3& shift, btScalar mass) {
// Parallel Axis Theorem says:
//
// Ishifted = Icm + M * [ (R*R)E - R(x)R ]
//
// So the inverse would be:
//
// Icm = Ishifted - M * [ (R*R)E - R(x)R ]
btScalar distanceSquared = shift.length2();
if (distanceSquared > btScalar(0.0f)) {
for (uint32_t i = 0; i < 3; ++i) {
btScalar shifti = shift[i];
inertia[i][i] -= mass * (distanceSquared - (shifti * shifti));
for (uint32_t j = i + 1; j < 3; ++j) {
btScalar offDiagonal = mass * shifti * shift[j];
inertia[i][j] += offDiagonal;
inertia[j][i] += offDiagonal;
}
}
}
}
MeshMassProperties::MeshMassProperties(const VectorOfPoints& points, const VectorOfIndices& triangleIndices) {
computeMassProperties(points, triangleIndices);
}
void MeshMassProperties::computeMassProperties(const VectorOfPoints& points, const VectorOfIndices& triangleIndices) {
// We process the mesh one triangle at a time. Each triangle defines a tetrahedron
// relative to some local point p0 (which we chose to be the local origin for convenience).
// Each tetrahedron contributes to the three totals: volume, centerOfMass, and inertiaTensor.
//
// We assume the mesh triangles are wound using the right-hand-rule, such that the
// triangle's points circle counter-clockwise about its face normal.
//
// initialize the totals
_volume = btScalar(0.0f);
btVector3 weightedCenter;
weightedCenter.setZero();
for (uint32_t i = 0; i < 3; ++i) {
_inertia[i].setZero();
}
// create some variables to hold temporary results
uint32_t numPoints = points.size();
const btVector3 p0(0.0f, 0.0f, 0.0f);
btMatrix3x3 tetraInertia;
btMatrix3x3 doubleDebugInertia;
btVector3 tetraPoints[4];
btVector3 center;
// loop over triangles
uint32_t numTriangles = triangleIndices.size() / 3;
for (uint32_t i = 0; i < numTriangles; ++i) {
uint32_t t = 3 * i;
assert(triangleIndices[t] < numPoints);
assert(triangleIndices[t + 1] < numPoints);
assert(triangleIndices[t + 2] < numPoints);
// extract raw vertices
tetraPoints[0] = p0;
tetraPoints[1] = points[triangleIndices[t]];
tetraPoints[2] = points[triangleIndices[t + 1]];
tetraPoints[3] = points[triangleIndices[t + 2]];
// compute volume
btScalar volume = computeTetrahedronVolume(tetraPoints);
// compute center
// NOTE: since tetraPoints[0] is the origin, we don't include it in the sum
center = btScalar(0.25f) * (tetraPoints[1] + tetraPoints[2] + tetraPoints[3]);
// shift vertices so that center of mass is at origin
tetraPoints[0] -= center;
tetraPoints[1] -= center;
tetraPoints[2] -= center;
tetraPoints[3] -= center;
// compute inertia tensor then shift it to origin-frame
computeTetrahedronInertia(volume, tetraPoints, tetraInertia);
applyParallelAxisTheorem(tetraInertia, center, volume);
// tally results
weightedCenter += volume * center;
_volume += volume;
_inertia += tetraInertia;
}
_centerOfMass = weightedCenter / _volume;
applyInverseParallelAxisTheorem(_inertia, _centerOfMass, _volume);
}

View file

@ -0,0 +1,61 @@
//
// MeshMassProperties.h
// libraries/physics/src
//
// Created by Andrew Meadows 2015.05.25
// 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
//
#ifndef hifi_MeshMassProperties_h
#define hifi_MeshMassProperties_h
#include <vector>
#include <stdint.h>
#include <btBulletDynamicsCommon.h>
typedef std::vector<btVector3> VectorOfPoints;
typedef std::vector<uint32_t> VectorOfIndices;
#define EXPOSE_HELPER_FUNCTIONS_FOR_UNIT_TEST
#ifdef EXPOSE_HELPER_FUNCTIONS_FOR_UNIT_TEST
void computeBoxInertia(btScalar mass, const btVector3& diagonal, btMatrix3x3& I);
// mass = input mass of tetrahedron
// points = input array of four points with center of mass at origin
// I = output inertia of tetrahedron about its center of mass
void computeTetrahedronInertia(btScalar mass, btVector3* points, btMatrix3x3& I);
void computeTetrahedronInertiaByBruteForce(btVector3* points, btMatrix3x3& I);
btScalar computeTetrahedronVolume(btVector3* points);
void applyParallelAxisTheorem(btMatrix3x3& inertia, const btVector3& shift, btScalar mass);
#endif // EXPOSE_HELPER_FUNCTIONS_FOR_UNIT_TEST
// Given a closed mesh with right-hand triangles a MeshMassProperties instance will compute
// its mass properties:
//
// volume
// center-of-mass
// normalized interia tensor about center of mass
//
class MeshMassProperties {
public:
// the mass properties calculation is done in the constructor, so if the mesh is complex
// then the construction could be computationally expensiuve.
MeshMassProperties(const VectorOfPoints& points, const VectorOfIndices& triangleIndices);
// compute the mass properties of a new mesh
void computeMassProperties(const VectorOfPoints& points, const VectorOfIndices& triangleIndices);
// harveste the mass properties from these public data members
btScalar _volume = 1.0f;
btVector3 _centerOfMass = btVector3(0.0f, 0.0f, 0.0f);
btMatrix3x3 _inertia = btMatrix3x3(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
};
#endif // _hifi_MeshMassProperties_h

View file

@ -39,7 +39,7 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) {
// TODO: add back non-physical kinematic objects and step them forward here
}
void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) {
void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
assert(entity);
if (entity->shouldBePhysical()) {
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
@ -51,7 +51,7 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItem* entity) {
}
}
void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) {
void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) {
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
if (motionState) {
motionState->clearObjectBackPointer();
@ -62,7 +62,7 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) {
_pendingAdds.remove(entity);
}
void PhysicalEntitySimulation::changeEntityInternal(EntityItem* entity) {
void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
// queue incoming changes: from external sources (script, EntityServer, etc) to physics engine
assert(entity);
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
@ -99,7 +99,7 @@ void PhysicalEntitySimulation::clearEntitiesInternal() {
// first disconnect each MotionStates from its Entity
for (auto stateItr : _physicalObjects) {
EntityMotionState* motionState = static_cast<EntityMotionState*>(&(*stateItr));
EntityItem* entity = motionState->getEntity();
EntityItemPointer entity = motionState->getEntity();
if (entity) {
entity->setPhysicsInfo(nullptr);
}
@ -125,7 +125,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToDelete() {
_pendingChanges.remove(motionState);
_physicalObjects.remove(motionState);
EntityItem* entity = motionState->getEntity();
EntityItemPointer entity = motionState->getEntity();
if (entity) {
_pendingAdds.remove(entity);
entity->setPhysicsInfo(nullptr);
@ -141,7 +141,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() {
_tempVector.clear();
SetOfEntities::iterator entityItr = _pendingAdds.begin();
while (entityItr != _pendingAdds.end()) {
EntityItem* entity = *entityItr;
EntityItemPointer entity = *entityItr;
assert(!entity->getPhysicsInfo());
if (!entity->shouldBePhysical()) {
// this entity should no longer be on the internal _pendingAdds
@ -186,7 +186,7 @@ void PhysicalEntitySimulation::handleOutgoingChanges(VectorOfMotionStates& motio
ObjectMotionState* state = &(*stateItr);
if (state && state->getType() == MOTIONSTATE_TYPE_ENTITY) {
EntityMotionState* entityState = static_cast<EntityMotionState*>(state);
EntityItem* entity = entityState->getEntity();
EntityItemPointer entity = entityState->getEntity();
if (entity) {
if (entityState->isCandidateForOwnership(sessionID)) {
_outgoingChanges.insert(entityState);

View file

@ -35,9 +35,9 @@ public:
protected: // only called by EntitySimulation
// overrides for EntitySimulation
virtual void updateEntitiesInternal(const quint64& now);
virtual void addEntityInternal(EntityItem* entity);
virtual void removeEntityInternal(EntityItem* entity);
virtual void changeEntityInternal(EntityItem* entity);
virtual void addEntityInternal(EntityItemPointer entity);
virtual void removeEntityInternal(EntityItemPointer entity);
virtual void changeEntityInternal(EntityItemPointer entity);
virtual void clearEntitiesInternal();
public:

View file

@ -15,6 +15,9 @@
#include <glm/glm.hpp>
#include <functional>
#include <render/Scene.h>
#include <render/Engine.h>
#include <QtGlobal>
class Transform;
@ -60,6 +63,10 @@ public:
virtual void postLambdaEvent(std::function<void()> f) = 0;
virtual qreal getDevicePixelRatio() = 0;
virtual render::ScenePointer getMain3DScene() = 0;
virtual render::EnginePointer getRenderEngine() = 0;
// FIXME - we shouldn't assume that there's a single instance of an AbstractViewStateInterface
static AbstractViewStateInterface* instance();
static void setInstance(AbstractViewStateInterface* instance);
};

View file

@ -11,29 +11,43 @@
#include "DrawTask.h"
#include <PerfStat.h>
#include "gpu/Batch.h"
#include "gpu/Context.h"
using namespace render;
DrawSceneTask::~DrawSceneTask() {
}
void DrawSceneTask::run(const SceneContextPointer& sceneContext) {
void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
// sanity checks
assert(sceneContext);
if (!sceneContext->_scene) {
return;
}
auto scene = sceneContext->_scene;
auto& scene = sceneContext->_scene;
auto itemBucketMap = scene->getMasterBucket();
auto& itemBucketMap = scene->getMasterBucket();
RenderArgs args;
RenderArgs* args = renderContext->args;
gpu::Batch theBatch;
args->_batch = &theBatch;
// render opaques
auto& opaqueShapeItems = itemBucketMap[ItemFilter::Builder::opaqueShape()];
auto filter = ItemFilter::Builder::opaqueShape();
auto& opaqueShapeItems = itemBucketMap.at(filter);
for (auto id : opaqueShapeItems) {
auto item = scene->getItem(id);
item.render(&args);
item.render(args);
}
args->_context->enqueueBatch((*args->_batch));
args->_batch = nullptr;
};

View file

@ -23,7 +23,7 @@ public:
DrawSceneTask() : Task() {}
~DrawSceneTask();
virtual void run(const SceneContextPointer& sceneContext);
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
};

View file

@ -10,11 +10,13 @@
//
#include "Engine.h"
#include "DrawTask.h"
using namespace render;
Engine::Engine() :
_sceneContext(new SceneContext())
_sceneContext(new SceneContext()),
_renderContext(new RenderContext())
{
}
@ -22,6 +24,10 @@ void Engine::registerScene(const ScenePointer& scene) {
_sceneContext->_scene = scene;
}
void Engine::setRenderContext(const RenderContext& renderContext) {
(*_renderContext) = renderContext;
}
void Engine::addTask(const TaskPointer& task) {
if (task) {
_tasks.push_back(task);
@ -30,9 +36,15 @@ void Engine::addTask(const TaskPointer& task) {
void Engine::run() {
for (auto task : _tasks) {
task->run(_sceneContext);
task->run(_sceneContext, _renderContext);
}
}
void Engine::buildStandardTaskPipeline() {
if (!_tasks.empty()) {
_tasks.clear();
}
addTask(TaskPointer(new DrawSceneTask()));
}

View file

@ -25,18 +25,25 @@ public:
};
typedef std::shared_ptr<SceneContext> SceneContextPointer;
class RenderContext {
public:
RenderArgs* args;
RenderContext() {}
};
typedef std::shared_ptr<RenderContext> RenderContextPointer;
// THe base class for a task that runs on the SceneContext
class Task {
public:
Task() {}
~Task() {}
virtual void run(const SceneContextPointer& sceneContext) {}
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {}
protected:
};
typedef std::shared_ptr<Task> TaskPointer;
typedef std::vector<TaskPointer> Tasks;
@ -51,21 +58,27 @@ public:
// Register the scene should be [art of the init phase before running the engine
void registerScene(const ScenePointer& scene);
// Push a RenderContext
void setRenderContext(const RenderContext& renderContext);
void addTask(const TaskPointer& task);
const Tasks& getTasks() const { return _tasks; }
void run();
// standard pipeline of tasks
void buildStandardTaskPipeline();
protected:
Tasks _tasks;
SceneContextPointer _sceneContext;
RenderContextPointer _renderContext;
};
typedef std::shared_ptr<Engine> EnginePointer;
}
#endif // hifi_render_Engine_h

Some files were not shown because too many files have changed in this diff Show more