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:
commit
bca80addef
110 changed files with 2302 additions and 1362 deletions
CMakeLists.txt
domain-server/resources/web/settings/js
examples
interface/src
Application.cppApplication.h
avatar
Avatar.cppAvatar.hAvatarManager.cppAvatarManager.hModelReferential.cppModelReferential.hMyAvatar.cppMyAvatar.h
devices
ui/overlays
libraries
avatars/src
entities-renderer
CMakeLists.txt
src
EntityTreeRenderer.cppEntityTreeRenderer.hRenderableBoxEntityItem.cppRenderableBoxEntityItem.hRenderableEntityItem.cppRenderableEntityItem.hRenderableLightEntityItem.cppRenderableLightEntityItem.hRenderableLineEntityItem.cppRenderableLineEntityItem.hRenderableModelEntityItem.cppRenderableModelEntityItem.hRenderableParticleEffectEntityItem.cppRenderableParticleEffectEntityItem.hRenderableSphereEntityItem.cppRenderableSphereEntityItem.hRenderableTextEntityItem.cppRenderableTextEntityItem.hRenderableWebEntityItem.cppRenderableWebEntityItem.hRenderableZoneEntityItem.cppRenderableZoneEntityItem.h
entities/src
AddEntityOperator.cppAddEntityOperator.hBoxEntityItem.cppBoxEntityItem.hDeleteEntityOperator.cppDeleteEntityOperator.hEntityItem.cppEntityScriptingInterface.cppEntityScriptingInterface.hEntitySimulation.cppEntitySimulation.hEntityTree.cppEntityTree.hEntityTreeElement.cppEntityTreeElement.hEntityTypes.cppEntityTypes.hLightEntityItem.cppLightEntityItem.hLineEntityItem.cppLineEntityItem.hModelEntityItem.cppModelEntityItem.hMovingEntitiesOperator.cppMovingEntitiesOperator.hParticleEffectEntityItem.cppParticleEffectEntityItem.hRecurseOctreeToMapOperator.cppSimpleEntitySimulation.cppSimpleEntitySimulation.hSphereEntityItem.cppSphereEntityItem.hTextEntityItem.cppTextEntityItem.hUpdateEntityOperator.cppUpdateEntityOperator.hWebEntityItem.cppWebEntityItem.hZoneEntityItem.cppZoneEntityItem.h
networking/src
physics/src
EntityMotionState.cppEntityMotionState.hMeshInfo.cppMeshInfo.hMeshMassProperties.cppMeshMassProperties.hPhysicalEntitySimulation.cppPhysicalEntitySimulation.h
render-utils/src
render/src/render
|
@ -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.
|
||||
|
|
|
@ -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
0
examples/blockWorld.js
Normal 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);
|
||||
|
|
53
examples/example/entityCollisionExample.js
Normal file
53
examples/example/entityCollisionExample.js
Normal 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);
|
||||
});
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
#include <GlowEffect.h>
|
||||
|
||||
#include "../../Menu.h"
|
||||
|
||||
#include "ModelOverlay.h"
|
||||
|
||||
ModelOverlay::ModelOverlay()
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_AvatarData_h
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
/* VS2010 defines stdint.h, but not inttypes.h */
|
||||
#if defined(_MSC_VER)
|
||||
typedef signed char int8_t;
|
||||
|
@ -57,6 +58,10 @@ typedef unsigned long long quint64;
|
|||
#include "Recorder.h"
|
||||
#include "Referential.h"
|
||||
|
||||
typedef std::shared_ptr<AvatarData> AvatarSharedPointer;
|
||||
typedef std::weak_ptr<AvatarData> AvatarWeakPointer;
|
||||
typedef QHash<QUuid, AvatarSharedPointer> AvatarHash;
|
||||
|
||||
// avatar motion behaviors
|
||||
const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0;
|
||||
const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1;
|
||||
|
|
|
@ -16,16 +16,14 @@
|
|||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <Node.h>
|
||||
|
||||
#include "AvatarData.h"
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
typedef QSharedPointer<AvatarData> AvatarSharedPointer;
|
||||
typedef QWeakPointer<AvatarData> AvatarWeakPointer;
|
||||
typedef QHash<QUuid, AvatarSharedPointer> AvatarHash;
|
||||
|
||||
class AvatarHashMap : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
38
libraries/entities-renderer/src/RenderableEntityItem.cpp
Normal file
38
libraries/entities-renderer/src/RenderableEntityItem.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
33
libraries/entities-renderer/src/RenderableEntityItem.h
Normal file
33
libraries/entities-renderer/src/RenderableEntityItem.h
Normal 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
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) { }
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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) :
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) :
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "AddEntityOperator.h"
|
||||
|
||||
AddEntityOperator::AddEntityOperator(EntityTree* tree,
|
||||
EntityItem* newEntity) :
|
||||
EntityItemPointer newEntity) :
|
||||
_tree(tree),
|
||||
_newEntity(newEntity),
|
||||
_foundNew(false),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
class EntityToDeleteDetails {
|
||||
public:
|
||||
EntityItem* entity;
|
||||
EntityItemPointer entity;
|
||||
AACube cube;
|
||||
EntityTreeElement* containingElement;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) << "--------------------------------------------------";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) { \
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) :
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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...
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) :
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
UpdateEntityOperator::UpdateEntityOperator(EntityTree* tree,
|
||||
EntityTreeElement* containingElement,
|
||||
EntityItem* existingEntity,
|
||||
EntityItemPointer existingEntity,
|
||||
const EntityItemProperties& properties) :
|
||||
_tree(tree),
|
||||
_existingEntity(existingEntity),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) :
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) :
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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()
|
||||
<< "---------------------------------------------";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
321
libraries/physics/src/MeshMassProperties.cpp
Normal file
321
libraries/physics/src/MeshMassProperties.cpp
Normal 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);
|
||||
}
|
||||
|
61
libraries/physics/src/MeshMassProperties.h
Normal file
61
libraries/physics/src/MeshMassProperties.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
DrawSceneTask() : Task() {}
|
||||
~DrawSceneTask();
|
||||
|
||||
virtual void run(const SceneContextPointer& sceneContext);
|
||||
virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue