Merge branch 'master' of https://github.com/highfidelity/hifi into domain-dtls

This commit is contained in:
Stephen Birarda 2015-05-29 12:06:12 -07:00
commit 2207bfaf40
139 changed files with 3701 additions and 1557 deletions

View file

@ -40,7 +40,8 @@ if (WIN32)
endif ()
message (WINDOW_SDK_PATH= ${WINDOW_SDK_PATH})
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${WINDOW_SDK_PATH})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
# /wd4351 disables warning C4351: new behavior: elements of array will be default initialized
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4351")
# /LARGEADDRESSAWARE enables 32-bit apps to use more than 2GB of memory.
# Caveats: http://stackoverflow.com/questions/2288728/drawbacks-of-using-largeaddressaware-for-32-bit-windows-executables
# TODO: Remove when building 64-bit.
@ -179,6 +180,7 @@ option(GET_TBB "Get Threading Building Blocks library automatically as external
option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
option(USE_NSIGHT "Attempt to find the nSight libraries" 1)
option(GET_VHACD "Get V-HACD library automatically as external project" 1)
option(GET_POLYVOX "Get polyvox library automatically as external project" 1)
if (WIN32)
option(GET_GLEW "Get GLEW library automatically as external project" 1)

View file

@ -1,6 +1,6 @@
#
# OSXTBBInstallNameChange.cmake
# cmake/externals/tbb
# OSXInstallNameChange.cmake
# cmake/macros
#
# Copyright 2015 High Fidelity, Inc.
# Created by Stephen Birarda on February 20, 2014
@ -10,36 +10,33 @@
#
# first find the so files in the source dir
set(_TBB_LIBRARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib)
file(GLOB_RECURSE _TBB_LIBRARIES "${_TBB_LIBRARY_DIR}/*.dylib")
message("INSTALL_NAME_LIBRARY_DIR ${INSTALL_NAME_LIBRARY_DIR}")
# raise an error if we found none
if (NOT _TBB_LIBRARIES)
message(FATAL_ERROR "Did not find any TBB libraries")
file(GLOB_RECURSE _LIBRARIES "${INSTALL_NAME_LIBRARY_DIR}/*.dylib")
if (NOT _LIBRARIES)
message(FATAL_ERROR "OSXInstallNameChange -- no libraries found: ${INSTALL_NAME_LIBRARY_DIR}")
endif ()
# find the install_name_tool command
find_program(INSTALL_NAME_TOOL_COMMAND NAMES install_name_tool DOC "Path to the install_name_tool command")
# find the lipo command
find_program(LIPO_COMMAND NAMES lipo DOC "Path to the lipo command")
# enumerate the libraries
foreach(_TBB_LIBRARY ${_TBB_LIBRARIES})
get_filename_component(_TBB_LIBRARY_FILENAME ${_TBB_LIBRARY} NAME)
foreach(_LIBRARY ${_LIBRARIES})
get_filename_component(_LIBRARY_FILENAME ${_LIBRARY} NAME)
set(_INSTALL_NAME_ARGS ${INSTALL_NAME_TOOL_COMMAND} -id ${_TBB_LIBRARY} ${_TBB_LIBRARY_FILENAME})
set(_INSTALL_NAME_ARGS ${INSTALL_NAME_TOOL_COMMAND} -id ${_LIBRARY} ${_LIBRARY_FILENAME})
message(STATUS "${INSTALL_NAME_COMMAND} ${_INSTALL_NAME_ARGS}")
execute_process(
COMMAND ${INSTALL_NAME_COMMAND} ${_INSTALL_NAME_ARGS}
WORKING_DIRECTORY ${_TBB_LIBRARY_DIR}
WORKING_DIRECTORY ${INSTALL_NAME_LIBRARY_DIR}
ERROR_VARIABLE _INSTALL_NAME_ERROR
)
if (_INSTALL_NAME_ERROR)
message(FATAL_ERROR "There was an error changing install name for ${_TBB_LIBRARY_FILENAME} - ${_INSTALL_NAME_ERROR}")
message(FATAL_ERROR "There was an error changing install name for ${_LIBRARY_FILENAME} - ${_INSTALL_NAME_ERROR}")
endif ()
endforeach()

57
cmake/externals/polyvox/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,57 @@
set(EXTERNAL_NAME polyvox)
include(ExternalProject)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://hifi-public.s3.amazonaws.com/dependencies/polyvox-master-2015-5-27.zip
URL_MD5 e3dd09a24df4db29ba370e3bea753388
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build
LOG_DOWNLOAD 1
LOG_CONFIGURE 1
LOG_BUILD 1
)
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
if (APPLE)
set(INSTALL_NAME_LIBRARY_DIR ${INSTALL_DIR}/lib)
message(STATUS "in polyvox INSTALL_NAME_LIBRARY_DIR ${INSTALL_NAME_LIBRARY_DIR}")
ExternalProject_Add_Step(
${EXTERNAL_NAME}
change-install-name
COMMENT "Calling install_name_tool on libraries to fix install name for dylib linking"
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${INSTALL_NAME_LIBRARY_DIR} -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
DEPENDEES install
WORKING_DIRECTORY <SOURCE_DIR>
LOG 1
)
endif ()
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
if (WIN32)
set(${EXTERNAL_NAME_UPPER}_CORE_INCLUDE_DIRS ${INSTALL_DIR}/PolyVoxCore/include CACHE FILEPATH
"Path to polyvox core include directory")
set(${EXTERNAL_NAME_UPPER}_UTIL_INCLUDE_DIRS ${INSTALL_DIR}/PolyVoxUtil/include CACHE FILEPATH
"Path to polyvox util include directory")
else ()
set(${EXTERNAL_NAME_UPPER}_CORE_INCLUDE_DIRS ${INSTALL_DIR}/include/PolyVoxCore CACHE FILEPATH
"Path to polyvox core include directory")
set(${EXTERNAL_NAME_UPPER}_UTIL_INCLUDE_DIRS ${INSTALL_DIR}/include/PolyVoxUtil CACHE FILEPATH
"Path to polyvox util include directory")
endif ()
if (WIN32)
set(${EXTERNAL_NAME_UPPER}_CORE_LIBRARY ${INSTALL_DIR}/PolyVoxCore/lib/PolyVoxCore.lib CACHE FILEPATH "polyvox core library")
# set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY ${INSTALL_DIR}/PolyVoxUtil/lib/PolyVoxUtil.lib CACHE FILEPATH "polyvox util library")
elseif (APPLE)
set(${EXTERNAL_NAME_UPPER}_CORE_LIBRARY ${INSTALL_DIR}/lib/libPolyVoxCore.dylib CACHE FILEPATH "polyvox core library")
# set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY ${INSTALL_DIR}/lib/libPolyVoxUtil.dylib CACHE FILEPATH "polyvox util library")
else ()
set(${EXTERNAL_NAME_UPPER}_CORE_LIBRARY ${INSTALL_DIR}/lib/libPolyVoxCore.so CACHE FILEPATH "polyvox core library")
# set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY ${INSTALL_DIR}/lib/libPolyVoxUtil.so CACHE FILEPATH "polyvox util library")
endif ()

View file

@ -66,7 +66,7 @@ if (APPLE)
${EXTERNAL_NAME}
change-install-name
COMMENT "Calling install_name_tool on TBB libraries to fix install name for dylib linking"
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/OSXTBBInstallNameChange.cmake
COMMAND ${CMAKE_COMMAND} -DINSTALL_NAME_LIBRARY_DIR=${_TBB_LIB_DIR} -P ${EXTERNAL_PROJECT_DIR}/OSXInstallNameChange.cmake
DEPENDEES install
WORKING_DIRECTORY <SOURCE_DIR>
LOG 1
@ -115,4 +115,4 @@ endif ()
if (DEFINED ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE)
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SOURCE_DIR}/include CACHE TYPE "List of tbb include directories")
endif ()
endif ()

View file

@ -0,0 +1,54 @@
#
# FindPolyvox.cmake
#
# Try to find the libpolyvox resampling library
#
# You can provide a LIBPOLYVOX_ROOT_DIR which contains lib and include directories
#
# Once done this will define
#
# POLYVOX_FOUND - system found libpolyvox
# POLYVOX_INCLUDE_DIRS - the libpolyvox include directory
# POLYVOX_LIBRARIES - link to this to use libpolyvox
#
# Created on 1/22/2015 by Stephen Birarda
# 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("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("polyvox")
find_path(POLYVOX_CORE_INCLUDE_DIRS PolyVoxCore/SimpleVolume.h PATH_SUFFIXES include include/PolyVoxCore HINTS ${POLYVOX_SEARCH_DIRS})
# find_path(POLYVOX_UTIL_INCLUDE_DIRS PolyVoxUtil/Serialization.h PATH_SUFFIXES include include/PolyVoxUtil HINTS ${POLYVOX_SEARCH_DIRS})
find_library(POLYVOX_CORE_LIBRARY NAMES PolyVoxCore PATH_SUFFIXES lib HINTS ${POLYVOX_SEARCH_DIRS})
# find_library(POLYVOX_UTIL_LIBRARY NAMES PolyVoxUtil PATH_SUFFIXES lib HINTS ${POLYVOX_SEARCH_DIRS})
# if (WIN32)
# find_path(POLYVOX_DLL_PATH polyvox.dll PATH_SUFFIXES bin HINTS ${POLYVOX_SEARCH_DIRS})
# endif()
# set(POLYVOX_REQUIREMENTS POLYVOX_CORE_INCLUDE_DIRS POLYVOX_UTIL_INCLUDE_DIRS POLYVOX_CORE_LIBRARY POLYVOX_UTIL_LIBRARY)
set(POLYVOX_REQUIREMENTS POLYVOX_CORE_INCLUDE_DIRS POLYVOX_CORE_LIBRARY)
# if (WIN32)
# list(APPEND POLYVOX_REQUIREMENTS POLYVOX_DLL_PATH)
# endif ()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Polyvox DEFAULT_MSG ${POLYVOX_REQUIREMENTS})
# if (WIN32)
# add_paths_to_fixup_libs(${POLYVOX_DLL_PATH})
# endif ()
# set(POLYVOX_INCLUDE_DIRS ${POLYVOX_CORE_INCLUDE_DIRS} ${POLYVOX_UTIL_INCLUDE_DIRS})
# set(POLYVOX_LIBRARIES ${POLYVOX_CORE_LIBRARY} ${POLYVOX_UTIL_LIBRARY})
set(POLYVOX_INCLUDE_DIRS ${POLYVOX_CORE_INCLUDE_DIRS})
set(POLYVOX_LIBRARIES ${POLYVOX_CORE_LIBRARY})
mark_as_advanced(POLYVOX_INCLUDE_DIRS POLYVOX_LIBRARIES POLYVOX_SEARCH_DIRS)

View file

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

201
examples/blockWorld.js Normal file
View file

@ -0,0 +1,201 @@
// blockWorld.js
// examples
//
// Created by Eric Levin on May 26, 2015
// Copyright 2015 High Fidelity, Inc.
//
// Creates a floor of tiles and then drops planky blocks at random points above the tile floor
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var TILE_SIZE = 7
var GENERATE_INTERVAL = 50;
var NUM_ROWS = 10;
var angVelRange = 4;
var floorTiles = [];
var blocks = [];
var blockSpawner;
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var floorPos = Vec3.sum(MyAvatar.position, {
x: 0,
y: -2,
z: 0
});
var x = floorPos.x;
var currentRowIndex = 0;
var currentColumnIndex = 0;
var DROP_HEIGHT = floorPos.y + 5;
var BLOCK_GRAVITY = {
x: 0,
y: -9,
z: 0
};
var BLOCK_SIZE = {
x: 0.2,
y: 0.1,
z: 0.8
};
var bounds = {
xMin: floorPos.x,
xMax: floorPos.x + (TILE_SIZE * NUM_ROWS) - TILE_SIZE,
zMin: floorPos.z,
zMax: floorPos.z + (TILE_SIZE * NUM_ROWS) - TILE_SIZE
};
var screenSize = Controller.getViewportDimensions();
var BUTTON_SIZE = 32;
var PADDING = 3;
var offButton = 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/close.png",
color: {
red: 255,
green: 255,
blue: 255
},
alpha: 1
});
var deleteButton = Overlays.addOverlay("image", {
x: screenSize.x / 2 - BUTTON_SIZE,
y: screenSize.y - (BUTTON_SIZE + PADDING),
width: BUTTON_SIZE,
height: BUTTON_SIZE,
imageURL: HIFI_PUBLIC_BUCKET + "images/delete.png",
color: {
red: 255,
green: 255,
blue: 255
},
alpha: 1
});
function generateFloor() {
for (var z = floorPos.z; currentColumnIndex < NUM_ROWS; z += TILE_SIZE, currentColumnIndex++) {
floorTiles.push(Entities.addEntity({
type: 'Box',
position: {
x: x,
y: floorPos.y,
z: z
},
dimensions: {
x: TILE_SIZE,
y: 2,
z: TILE_SIZE
},
color: {
red: randFloat(70, 120),
green: randFloat(70, 71),
blue: randFloat(70, 80)
},
// collisionsWillMove: true
}));
}
currentRowIndex++;
if (currentRowIndex < NUM_ROWS) {
currentColumnIndex = 0;
x += TILE_SIZE;
Script.setTimeout(generateFloor, GENERATE_INTERVAL);
} else {
//Once we're done generating floor, drop planky blocks at random points on floor
blockSpawner = Script.setInterval(function() {
dropBlock();
}, GENERATE_INTERVAL)
}
}
function dropBlock() {
var dropPos = floorPos;
dropPos.y = DROP_HEIGHT;
dropPos.x = randFloat(bounds.xMin, bounds.xMax);
dropPos.z = randFloat(bounds.zMin, bounds.zMax);
blocks.push(Entities.addEntity({
type: "Model",
modelURL: 'http://s3.amazonaws.com/hifi-public/marketplace/hificontent/Games/blocks/block.fbx',
shapeType: 'box',
position: dropPos,
dimensions: BLOCK_SIZE,
collisionsWillMove: true,
gravity: {
x: 0,
y: -9,
z: 0
},
velocity: {
x: 0,
y: .1,
z: 0
},
angularVelocity: {
x: randFloat(-angVelRange, angVelRange),
y: randFloat(-angVelRange, angVelRange),
z: randFloat(-angVelRange, angVelRange),
}
}));
}
function mousePressEvent(event) {
var clickedOverlay = Overlays.getOverlayAtPoint({
x: event.x,
y: event.y
});
if (clickedOverlay == offButton) {
Script.clearInterval(blockSpawner);
}
if(clickedOverlay == deleteButton){
destroyStuff();
}
}
generateFloor();
function cleanup() {
// for (var i = 0; i < floorTiles.length; i++) {
// Entities.deleteEntity(floorTiles[i]);
// }
// for (var i = 0; i < blocks.length; i++) {
// Entities.deleteEntity(blocks[i]);
// }
Overlays.deleteOverlay(offButton);
Overlays.deleteOverlay(deleteButton)
Script.clearInterval(blockSpawner);
}
function destroyStuff() {
for (var i = 0; i < floorTiles.length; i++) {
Entities.deleteEntity(floorTiles[i]);
}
for (var i = 0; i < blocks.length; i++) {
Entities.deleteEntity(blocks[i]);
}
Script.clearInterval(blockSpawner);
}
function randFloat(low, high) {
return Math.floor(low + Math.random() * (high - low));
}
function map(value, min1, max1, min2, max2) {
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
}
Script.scriptEnding.connect(cleanup);
Controller.mousePressEvent.connect(mousePressEvent);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,9 +1,74 @@
// 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;
function calculateNearLinePosition(targetPosition) {
var handPosition = MyAvatar.getRightPalmPosition();
var along = Vec3.subtract(targetPosition, handPosition);
along = Vec3.normalize(along);
@ -22,30 +87,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 +127,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 +199,13 @@ function mousePressEvent(event) {
}
function mouseMoveEvent(event) {
createOrUpdateLine(event);
}
function mouseReleaseEvent(event) {
if (!lineCreated) {
return;
@ -91,7 +228,17 @@ function keyReleaseEvent(event) {
}
function cleanup() {
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);

43
examples/voxels.js Normal file
View file

@ -0,0 +1,43 @@
var controlHeld = false;
function mousePressEvent(event) {
if (!event.isLeftButton) {
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 ids = Entities.findEntities(intersection.intersection, 10);
for (var i = 0; i < ids.length; i++) {
var id = ids[i];
if (controlHeld) {
Entities.setVoxelSphere(id, intersection.intersection, 1.2, 0);
} else {
Entities.setVoxelSphere(id, intersection.intersection, 1.2, 255);
}
}
}
}
function keyPressEvent(event) {
if (event.text == "CONTROL") {
controlHeld = true;
}
}
function keyReleaseEvent(event) {
if (event.text == "CONTROL") {
controlHeld = false;
}
}
Controller.mousePressEvent.connect(mousePressEvent);
Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent);

View file

@ -687,6 +687,10 @@ Application::~Application() {
// stop the glWidget frame timer so it doesn't call paintGL
_glWidget->stopFrameTimer();
// remove avatars from physics engine
DependencyManager::get<AvatarManager>()->clearOtherAvatars();
_physicsEngine.deleteObjects(DependencyManager::get<AvatarManager>()->getObjectsToDelete());
DependencyManager::destroy<OffscreenUi>();
DependencyManager::destroy<AvatarManager>();
DependencyManager::destroy<AnimationCache>();
@ -1944,7 +1948,9 @@ FaceTracker* Application::getSelectedFaceTracker() {
}
void Application::setActiveFaceTracker() {
#if defined(HAVE_FACESHIFT) || defined(HAVE_DDE)
bool isMuted = Menu::getInstance()->isOptionChecked(MenuOption::MuteFaceTracking);
#endif
#ifdef HAVE_FACESHIFT
auto faceshiftTracker = DependencyManager::get<Faceshift>();
faceshiftTracker->setIsMuted(isMuted);
@ -1970,7 +1976,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;
@ -2011,7 +2017,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) {
@ -2150,14 +2156,11 @@ void Application::init() {
_physicsEngine.init();
EntityTree* tree = _entities.getTree();
_entitySimulation.init(tree, &_physicsEngine, &_shapeManager, &_entityEditSender);
_entitySimulation.init(tree, &_physicsEngine, &_entityEditSender);
tree->setSimulation(&_entitySimulation);
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);
@ -2180,6 +2183,9 @@ void Application::init() {
// initialize the GlowEffect with our widget
bool glow = Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect);
DependencyManager::get<GlowEffect>()->init(glow);
// Make sure any new sounds are loaded as soon as know about them.
connect(tree, &EntityTree::newCollisionSoundURL, DependencyManager::get<SoundCache>().data(), &SoundCache::getSound);
}
void Application::closeMirrorView() {
@ -2470,23 +2476,33 @@ void Application::update(float deltaTime) {
_physicsEngine.changeObjects(_entitySimulation.getObjectsToChange());
_entitySimulation.unlock();
AvatarManager* avatarManager = DependencyManager::get<AvatarManager>().data();
_physicsEngine.deleteObjects(avatarManager->getObjectsToDelete());
_physicsEngine.addObjects(avatarManager->getObjectsToAdd());
_physicsEngine.changeObjects(avatarManager->getObjectsToChange());
_physicsEngine.stepSimulation();
if (_physicsEngine.hasOutgoingChanges()) {
_entitySimulation.lock();
_entitySimulation.handleOutgoingChanges(_physicsEngine.getOutgoingChanges(), _physicsEngine.getSessionID());
_entitySimulation.unlock();
_physicsEngine.dumpStatsIfNecessary();
}
}
if (!_aboutToQuit) {
PerformanceTimer perfTimer("entities");
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk deadlock.)
_entitySimulation.handleCollisionEvents(_physicsEngine.getCollisionEvents());
// NOTE: the _entities.update() call below will wait for lock
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
_entities.update(); // update the models...
avatarManager->handleOutgoingChanges(_physicsEngine.getOutgoingChanges());
auto collisionEvents = _physicsEngine.getCollisionEvents();
avatarManager->handleCollisionEvents(collisionEvents);
_physicsEngine.dumpStatsIfNecessary();
if (!_aboutToQuit) {
PerformanceTimer perfTimer("entities");
// Collision events (and their scripts) must not be handled when we're locked, above. (That would risk deadlock.)
_entitySimulation.handleCollisionEvents(collisionEvents);
// NOTE: the _entities.update() call below will wait for lock
// and will simulate entity motion (the EntityTree has been given an EntitySimulation).
_entities.update(); // update the models...
}
}
}
{

View file

@ -38,6 +38,7 @@
#include "Application.h"
#include "Avatar.h"
#include "AvatarManager.h"
#include "AvatarMotionState.h"
#include "Hand.h"
#include "Head.h"
#include "Menu.h"
@ -972,6 +973,9 @@ int Avatar::parseDataAtOffset(const QByteArray& packet, int offset) {
const float MOVE_DISTANCE_THRESHOLD = 0.001f;
_moving = glm::distance(oldPosition, _position) > MOVE_DISTANCE_THRESHOLD;
if (_moving && _motionState) {
_motionState->addDirtyFlags(EntityItem::DIRTY_POSITION);
}
return bytesRead;
}
@ -1087,20 +1091,15 @@ void Avatar::setShowDisplayName(bool showDisplayName) {
}
// virtual
void Avatar::rebuildSkeletonBody() {
/* TODO: implement this and remove override from MyAvatar (when we have AvatarMotionStates working)
if (_motionState) {
// compute localAABox
const CapsuleShape& capsule = _skeletonModel.getBoundingShape();
float radius = capsule.getRadius();
float height = 2.0f * (capsule.getHalfHeight() + radius);
glm::vec3 corner(-radius, -0.5f * height, -radius);
corner += _skeletonModel.getBoundingShapeOffset();
glm::vec3 scale(2.0f * radius, height, 2.0f * radius);
//_characterController.setLocalBoundingBox(corner, scale);
_motionState->setBoundingBox(corner, scale);
}
*/
// virtual
void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) {
const CapsuleShape& capsule = _skeletonModel.getBoundingShape();
shapeInfo.setCapsuleY(capsule.getRadius(), capsule.getHalfHeight());
shapeInfo.setOffset(_skeletonModel.getBoundingShapeOffset());
}
// virtual
void Avatar::rebuildSkeletonBody() {
DependencyManager::get<AvatarManager>()->updateAvatarPhysicsShape(getSessionUUID());
}

View file

@ -18,11 +18,11 @@
#include <QtCore/QUuid>
#include <AvatarData.h>
#include <ShapeInfo.h>
#include "Hand.h"
#include "Head.h"
#include "InterfaceConfig.h"
#include "Recorder.h"
#include "SkeletonModel.h"
#include "world.h"
@ -55,6 +55,7 @@ enum ScreenTintLayer {
NUM_SCREEN_TINT_LAYERS
};
class AvatarMotionState;
class Texture;
class Avatar : public AvatarData {
@ -164,6 +165,10 @@ public:
virtual void rebuildSkeletonBody();
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
friend class AvatarManager;
signals:
void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision);
@ -231,7 +236,7 @@ private:
int _voiceSphereID;
//AvatarMotionState* _motionState = nullptr;
AvatarMotionState* _motionState = nullptr;
};
#endif // hifi_Avatar_h

View file

@ -92,22 +92,18 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
// simulate avatars
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {
AvatarSharedPointer sharedAvatar = avatarIterator.value();
Avatar* avatar = reinterpret_cast<Avatar*>(sharedAvatar.data());
Avatar* avatar = reinterpret_cast<Avatar*>(avatarIterator.value().data());
if (sharedAvatar == _myAvatar || !avatar->isInitialized()) {
if (avatar == _myAvatar || !avatar->isInitialized()) {
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
// DO NOT update uninitialized Avatars
// DO NOT update or fade out uninitialized Avatars
++avatarIterator;
continue;
}
if (!shouldKillAvatar(sharedAvatar)) {
// this avatar's mixer is still around, go ahead and simulate it
} else if (avatar->shouldDie()) {
_avatarFades.push_back(avatarIterator.value());
avatarIterator = _avatarHash.erase(avatarIterator);
} else {
avatar->simulate(deltaTime);
++avatarIterator;
} else {
// the mixer that owned this avatar is gone, give it to the vector of fades and kill it
avatarIterator = erase(avatarIterator);
}
}
@ -175,24 +171,52 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() {
return AvatarSharedPointer(new Avatar());
}
AvatarHash::iterator AvatarManager::erase(const AvatarHash::iterator& iterator) {
if (iterator.key() != MY_AVATAR_KEY) {
if (reinterpret_cast<Avatar*>(iterator.value().data())->isInitialized()) {
_avatarFades.push_back(iterator.value());
// virtual
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer);
return avatar;
}
// protected
void AvatarManager::removeAvatarMotionState(Avatar* avatar) {
AvatarMotionState* motionState= avatar->_motionState;
if (motionState) {
// clean up physics stuff
motionState->clearObjectBackPointer();
avatar->_motionState = nullptr;
_avatarMotionStates.remove(motionState);
_motionStatesToAdd.remove(motionState);
_motionStatesToDelete.push_back(motionState);
}
}
// virtual
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()) {
removeAvatarMotionState(avatar);
_avatarFades.push_back(avatarIterator.value());
_avatarHash.erase(avatarIterator);
}
return AvatarHashMap::erase(iterator);
} else {
// never remove _myAvatar from the list
AvatarHash::iterator returnIterator = iterator;
return ++returnIterator;
}
}
void AvatarManager::clearOtherAvatars() {
// clear any avatars that came from an avatar-mixer
AvatarHash::iterator removeAvatar = _avatarHash.begin();
while (removeAvatar != _avatarHash.end()) {
removeAvatar = erase(removeAvatar);
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {
Avatar* avatar = reinterpret_cast<Avatar*>(avatarIterator.value().data());
if (avatar == _myAvatar || !avatar->isInitialized()) {
// don't remove myAvatar or uninitialized avatars from the list
++avatarIterator;
} else {
removeAvatarMotionState(avatar);
_avatarFades.push_back(avatarIterator.value());
avatarIterator = _avatarHash.erase(avatarIterator);
}
}
_myAvatar->clearLookAtTargetAvatar();
}
@ -215,3 +239,57 @@ QVector<AvatarManager::LocalLight> AvatarManager::getLocalLights() const {
return _localLights;
}
VectorOfMotionStates& AvatarManager::getObjectsToDelete() {
_tempMotionStates.clear();
_tempMotionStates.swap(_motionStatesToDelete);
return _tempMotionStates;
}
VectorOfMotionStates& AvatarManager::getObjectsToAdd() {
_tempMotionStates.clear();
for (auto motionState : _motionStatesToAdd) {
_tempMotionStates.push_back(motionState);
}
_motionStatesToAdd.clear();
return _tempMotionStates;
}
VectorOfMotionStates& AvatarManager::getObjectsToChange() {
_tempMotionStates.clear();
for (auto state : _avatarMotionStates) {
if (state->_dirtyFlags > 0) {
_tempMotionStates.push_back(state);
}
}
return _tempMotionStates;
}
void AvatarManager::handleOutgoingChanges(VectorOfMotionStates& motionStates) {
// TODO: extract the MyAvatar results once we use a MotionState for it.
}
void AvatarManager::handleCollisionEvents(CollisionEvents& collisionEvents) {
// TODO: expose avatar collision events to JS
}
void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) {
AvatarHash::iterator avatarItr = _avatarHash.find(id);
if (avatarItr != _avatarHash.end()) {
Avatar* avatar = static_cast<Avatar*>(avatarItr.value().data());
AvatarMotionState* motionState = avatar->_motionState;
if (motionState) {
motionState->addDirtyFlags(EntityItem::DIRTY_SHAPE);
} else {
ShapeInfo shapeInfo;
avatar->computeShapeInfo(shapeInfo);
btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo);
if (shape) {
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
avatar->_motionState = motionState;
_motionStatesToAdd.insert(motionState);
_avatarMotionStates.insert(motionState);
}
}
}
}

View file

@ -17,8 +17,10 @@
#include <QtCore/QSharedPointer>
#include <AvatarHashMap.h>
#include <PhysicsEngine.h>
#include "Avatar.h"
#include "AvatarMotionState.h"
class MyAvatar;
@ -51,6 +53,14 @@ public:
Q_INVOKABLE void setLocalLights(const QVector<AvatarManager::LocalLight>& localLights);
Q_INVOKABLE QVector<AvatarManager::LocalLight> getLocalLights() const;
VectorOfMotionStates& getObjectsToDelete();
VectorOfMotionStates& getObjectsToAdd();
VectorOfMotionStates& getObjectsToChange();
void handleOutgoingChanges(VectorOfMotionStates& motionStates);
void handleCollisionEvents(CollisionEvents& collisionEvents);
void updateAvatarPhysicsShape(const QUuid& id);
public slots:
void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; }
@ -62,10 +72,11 @@ private:
void simulateAvatarFades(float deltaTime);
void renderAvatarFades(const glm::vec3& cameraPosition, RenderArgs::RenderMode renderMode);
AvatarSharedPointer newSharedAvatar();
// virtual overrides
AvatarHash::iterator erase(const AvatarHash::iterator& iterator);
virtual AvatarSharedPointer newSharedAvatar();
virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);
void removeAvatarMotionState(Avatar* avatar);
virtual void removeAvatar(const QUuid& sessionUUID);
QVector<AvatarSharedPointer> _avatarFades;
QSharedPointer<MyAvatar> _myAvatar;
@ -74,6 +85,11 @@ private:
QVector<AvatarManager::LocalLight> _localLights;
bool _shouldShowReceiveStats = false;
SetOfAvatarMotionStates _avatarMotionStates;
SetOfMotionStates _motionStatesToAdd;
VectorOfMotionStates _motionStatesToDelete;
VectorOfMotionStates _tempMotionStates;
};
Q_DECLARE_METATYPE(AvatarManager::LocalLight)

View file

@ -0,0 +1,160 @@
//
// AvatarMotionState.cpp
// interface/src/avatar/
//
// Created by Andrew Meadows 2015.05.14
// 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 <PhysicsHelpers.h>
#include "Avatar.h"
#include "AvatarMotionState.h"
#include "BulletUtil.h"
AvatarMotionState::AvatarMotionState(Avatar* avatar, btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
assert(_avatar);
if (_shape) {
_mass = 100.0f; // HACK
}
}
AvatarMotionState::~AvatarMotionState() {
_avatar = nullptr;
}
// virtual
uint32_t AvatarMotionState::getAndClearIncomingDirtyFlags() {
uint32_t dirtyFlags = 0;
if (_body && _avatar) {
dirtyFlags = _dirtyFlags;
_dirtyFlags = 0;
}
return dirtyFlags;
}
MotionType AvatarMotionState::computeObjectMotionType() const {
// TODO?: support non-DYNAMIC motion for avatars? (e.g. when sitting)
return MOTION_TYPE_DYNAMIC;
}
// virtual and protected
btCollisionShape* AvatarMotionState::computeNewShape() {
if (_avatar) {
ShapeInfo shapeInfo;
_avatar->computeShapeInfo(shapeInfo);
return getShapeManager()->getShape(shapeInfo);
}
return nullptr;
}
// virtual
bool AvatarMotionState::isMoving() const {
return false;
}
// virtual
void AvatarMotionState::getWorldTransform(btTransform& worldTrans) const {
if (!_avatar) {
return;
}
worldTrans.setOrigin(glmToBullet(getObjectPosition()));
worldTrans.setRotation(glmToBullet(getObjectRotation()));
if (_body) {
_body->setLinearVelocity(glmToBullet(getObjectLinearVelocity()));
_body->setAngularVelocity(glmToBullet(getObjectLinearVelocity()));
}
}
// virtual
void AvatarMotionState::setWorldTransform(const btTransform& worldTrans) {
if (!_avatar) {
return;
}
// HACK: The PhysicsEngine does not actually move OTHER avatars -- instead it slaves their local RigidBody to the transform
// as specified by a remote simulation. However, to give the remote simulation time to respond to our own objects we tie
// the other avatar's body to its true position with a simple spring. This is a HACK that will have to be improved later.
const float SPRING_TIMESCALE = 0.5f;
float tau = PHYSICS_ENGINE_FIXED_SUBSTEP / SPRING_TIMESCALE;
btVector3 currentPosition = worldTrans.getOrigin();
btVector3 targetPosition = glmToBullet(getObjectPosition());
btTransform newTransform;
newTransform.setOrigin((1.0f - tau) * currentPosition + tau * targetPosition);
newTransform.setRotation(glmToBullet(getObjectRotation()));
_body->setWorldTransform(newTransform);
_body->setLinearVelocity(glmToBullet(getObjectLinearVelocity()));
_body->setAngularVelocity(glmToBullet(getObjectLinearVelocity()));
}
// These pure virtual methods must be implemented for each MotionState type
// and make it possible to implement more complicated methods in this base class.
// virtual
float AvatarMotionState::getObjectRestitution() const {
return 0.5f;
}
// virtual
float AvatarMotionState::getObjectFriction() const {
return 0.5f;
}
// virtual
float AvatarMotionState::getObjectLinearDamping() const {
return 0.5f;
}
// virtual
float AvatarMotionState::getObjectAngularDamping() const {
return 0.5f;
}
// virtual
glm::vec3 AvatarMotionState::getObjectPosition() const {
return _avatar->getPosition();
}
// virtual
glm::quat AvatarMotionState::getObjectRotation() const {
return _avatar->getOrientation();
}
// virtual
glm::vec3 AvatarMotionState::getObjectLinearVelocity() const {
return _avatar->getVelocity();
}
// virtual
glm::vec3 AvatarMotionState::getObjectAngularVelocity() const {
return _avatar->getAngularVelocity();
}
// virtual
glm::vec3 AvatarMotionState::getObjectGravity() const {
return _avatar->getAcceleration();
}
// virtual
const QUuid& AvatarMotionState::getObjectID() const {
return _avatar->getSessionUUID();
}
// virtual
QUuid AvatarMotionState::getSimulatorID() const {
return _avatar->getSessionUUID();
}
// virtual
void AvatarMotionState::bump() {
}
// virtual
void AvatarMotionState::clearObjectBackPointer() {
ObjectMotionState::clearObjectBackPointer();
_avatar = nullptr;
}

View file

@ -0,0 +1,75 @@
//
// AvatarMotionState.h
// interface/src/avatar/
//
// Created by Andrew Meadows 2015.05.14
// 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_AvatarMotionState_h
#define hifi_AvatarMotionState_h
#include <QSet>
#include <ObjectMotionState.h>
class Avatar;
class AvatarMotionState : public ObjectMotionState {
public:
AvatarMotionState(Avatar* avatar, btCollisionShape* shape);
~AvatarMotionState();
virtual MotionType getMotionType() const { return _motionType; }
virtual uint32_t getAndClearIncomingDirtyFlags();
virtual MotionType computeObjectMotionType() const;
virtual bool isMoving() const;
// this relays incoming position/rotation to the RigidBody
virtual void getWorldTransform(btTransform& worldTrans) const;
// this relays outgoing position/rotation to the EntityItem
virtual void setWorldTransform(const btTransform& worldTrans);
// These pure virtual methods must be implemented for each MotionState type
// and make it possible to implement more complicated methods in this base class.
virtual float getObjectRestitution() const;
virtual float getObjectFriction() const;
virtual float getObjectLinearDamping() const;
virtual float getObjectAngularDamping() const;
virtual glm::vec3 getObjectPosition() const;
virtual glm::quat getObjectRotation() const;
virtual glm::vec3 getObjectLinearVelocity() const;
virtual glm::vec3 getObjectAngularVelocity() const;
virtual glm::vec3 getObjectGravity() const;
virtual const QUuid& getObjectID() const;
virtual QUuid getSimulatorID() const;
virtual void bump();
void setBoundingBox(const glm::vec3& corner, const glm::vec3& diagonal);
void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; }
friend class AvatarManager;
protected:
virtual btCollisionShape* computeNewShape();
virtual void clearObjectBackPointer();
Avatar* _avatar;
uint32_t _dirtyFlags;
};
typedef QSet<AvatarMotionState*> SetOfAvatarMotionStates;
#endif // hifi_AvatarMotionState_h

View file

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

View file

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

View file

@ -41,6 +41,7 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
_headClipDistance(DEFAULT_NEAR_CLIP)
{
assert(_owningAvatar);
_enableShapes = true;
}
SkeletonModel::~SkeletonModel() {

View file

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

View file

@ -356,7 +356,7 @@ void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) {
});
if (!Application::getInstance()->isMouseHidden()) {
renderPointersOculus(myAvatar->getDefaultEyePosition());
renderPointersOculus();
}
glDepthMask(GL_TRUE);
glDisable(GL_TEXTURE_2D);
@ -486,49 +486,40 @@ void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origi
direction = glm::normalize(intersectionWithUi - origin);
}
glm::vec2 getPolarCoordinates(const PalmData& palm) {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
auto avatarOrientation = myAvatar->getOrientation();
auto eyePos = myAvatar->getDefaultEyePosition();
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm);
// Direction of the tip relative to the eye
glm::vec3 tipDirection = tip - eyePos;
// orient into avatar space
tipDirection = glm::inverse(avatarOrientation) * tipDirection;
// Normalize for trig functions
tipDirection = glm::normalize(tipDirection);
// Convert to polar coordinates
glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y));
return polar;
}
//Caculate the click location using one of the sixense controllers. Scale is not applied
QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
glm::vec3 eyePos = myAvatar->getHead()->getEyePosition();
glm::quat invOrientation = glm::inverse(myAvatar->getOrientation());
//direction of ray goes towards camera
glm::vec3 dir = invOrientation * glm::normalize(qApp->getCamera()->getPosition() - tip);
glm::vec3 tipPos = invOrientation * (tip - eyePos);
QPoint rv;
auto canvasSize = qApp->getCanvasSize();
if (qApp->isHMDMode()) {
float t;
//We back the ray up by dir to ensure that it will not start inside the UI.
glm::vec3 adjustedPos = tipPos - dir;
//Find intersection of crosshair ray.
if (raySphereIntersect(dir, adjustedPos, _oculusUIRadius * myAvatar->getScale(), &t)){
glm::vec3 collisionPos = adjustedPos + dir * t;
//Normalize it in case its not a radius of 1
collisionPos = glm::normalize(collisionPos);
//If we hit the back hemisphere, mark it as not a collision
if (collisionPos.z > 0) {
rv.setX(INT_MAX);
rv.setY(INT_MAX);
} else {
float u = asin(collisionPos.x) / (_textureFov)+0.5f;
float v = 1.0 - (asin(collisionPos.y) / (_textureFov)+0.5f);
rv.setX(u * canvasSize.x);
rv.setY(v * canvasSize.y);
}
} else {
//if they did not click on the overlay, just set the coords to INT_MAX
rv.setX(INT_MAX);
rv.setY(INT_MAX);
}
glm::vec2 polar = getPolarCoordinates(*palm);
glm::vec2 point = sphericalToScreen(-polar);
rv.rx() = point.x;
rv.ry() = point.y;
} else {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::dmat4 projection;
qApp->getProjectionMatrix(&projection);
glm::quat invOrientation = glm::inverse(myAvatar->getOrientation());
glm::vec3 eyePos = myAvatar->getDefaultEyePosition();
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(palm);
glm::vec3 tipPos = invOrientation * (tip - eyePos);
glm::vec4 clipSpacePos = glm::vec4(projection * glm::dvec4(tipPos, 1.0));
glm::vec3 ndcSpacePos;
@ -729,7 +720,7 @@ void ApplicationOverlay::renderControllerPointers() {
}
}
void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) {
void ApplicationOverlay::renderPointersOculus() {
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
@ -737,16 +728,12 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) {
//Controller Pointers
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
PalmData& palm = myAvatar->getHand()->getPalms()[i];
if (palm.isActive()) {
glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm);
glm::vec3 tipDirection = glm::normalize(glm::inverse(myAvatar->getOrientation()) * (tip - eyePos));
float pitch = -glm::asin(tipDirection.y);
float yawSign = glm::sign(-tipDirection.x);
float yaw = glm::acos(-tipDirection.z) *
((yawSign == 0.0f) ? 1.0f : yawSign);
glm::quat orientation = glm::quat(glm::vec3(pitch, yaw, 0.0f));
glm::vec2 polar = getPolarCoordinates(palm);
// Convert to quaternion
glm::quat orientation = glm::quat(glm::vec3(polar.y, -polar.x, 0.0f));
// Render reticle at location
renderReticle(orientation, _alpha);
}
}

View file

@ -102,7 +102,7 @@ private:
void renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder);
void renderControllerPointers();
void renderPointersOculus(const glm::vec3& eyePos);
void renderPointersOculus();
void renderAudioMeter();
void renderCameraToggle();

View file

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

View file

@ -69,6 +69,7 @@ const quint32 AVATAR_MOTION_DEFAULTS =
const quint32 AVATAR_MOTION_SCRIPTABLE_BITS =
AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED;
const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND;
// Bitset of state flags - we store the key state, hand state, faceshift, chat circling, and existance of
// referential data in this bit set. The hand state is an octal, but is split into two sections to maintain
@ -290,7 +291,6 @@ public:
QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); }
void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); }
Node* getOwningAvatarMixer() { return _owningAvatarMixer.data(); }
void setOwningAvatarMixer(const QWeakPointer<Node>& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; }
const AABox& getLocalAABox() const { return _localAABox; }
@ -302,7 +302,9 @@ public:
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
glm::vec3 getTargetVelocity() const { return _targetVelocity; }
const glm::vec3& getTargetVelocity() const { return _targetVelocity; }
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
public slots:
void sendAvatarDataPacket();

View file

@ -20,19 +20,6 @@ AvatarHashMap::AvatarHashMap() {
connect(DependencyManager::get<NodeList>().data(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged);
}
AvatarHash::iterator AvatarHashMap::erase(const AvatarHash::iterator& iterator) {
qCDebug(avatars) << "Removing Avatar with UUID" << iterator.key() << "from AvatarHashMap.";
return _avatarHash.erase(iterator);
}
const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND;
bool AvatarHashMap::shouldKillAvatar(const AvatarSharedPointer& sharedAvatar) {
return (sharedAvatar->getOwningAvatarMixer() == NULL
|| sharedAvatar->getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS);
}
void AvatarHashMap::processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer) {
switch (packetTypeForPacket(datagram)) {
case PacketTypeBulkAvatarData:
@ -52,10 +39,6 @@ void AvatarHashMap::processAvatarMixerDatagram(const QByteArray& datagram, const
}
}
bool AvatarHashMap::containsAvatarWithDisplayName(const QString& displayName) {
return !avatarWithDisplayName(displayName).isNull();
}
bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range) {
foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) {
glm::vec3 avatarPosition = sharedAvatar->getPosition();
@ -67,45 +50,19 @@ bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range
return false;
}
AvatarWeakPointer AvatarHashMap::avatarWithDisplayName(const QString& displayName) {
foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) {
if (sharedAvatar->getDisplayName() == displayName) {
// this is a match
// check if this avatar should still be around
if (!shouldKillAvatar(sharedAvatar)) {
// we have a match, return the AvatarData
return sharedAvatar;
} else {
// we should remove this avatar, but we might not be on a thread that is allowed
// so we just return NULL to the caller
return AvatarWeakPointer();
}
}
}
return AvatarWeakPointer();
}
AvatarSharedPointer AvatarHashMap::newSharedAvatar() {
return AvatarSharedPointer(new AvatarData());
}
AvatarSharedPointer AvatarHashMap::matchingOrNewAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
AvatarSharedPointer matchingAvatar = _avatarHash.value(sessionUUID);
if (!matchingAvatar) {
// insert the new avatar into our hash
matchingAvatar = newSharedAvatar();
qCDebug(avatars) << "Adding avatar with sessionUUID " << sessionUUID << "to AvatarHashMap.";
matchingAvatar->setSessionUUID(sessionUUID);
matchingAvatar->setOwningAvatarMixer(mixerWeakPointer);
_avatarHash.insert(sessionUUID, matchingAvatar);
}
return matchingAvatar;
AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
qCDebug(avatars) << "Adding avatar with sessionUUID " << sessionUUID << "to AvatarHashMap.";
AvatarSharedPointer avatar = newSharedAvatar();
avatar->setSessionUUID(sessionUUID);
avatar->setOwningAvatarMixer(mixerWeakPointer);
_avatarHash.insert(sessionUUID, avatar);
return avatar;
}
void AvatarHashMap::processAvatarDataPacket(const QByteArray &datagram, const QWeakPointer<Node> &mixerWeakPointer) {
@ -118,10 +75,13 @@ void AvatarHashMap::processAvatarDataPacket(const QByteArray &datagram, const QW
bytesRead += NUM_BYTES_RFC4122_UUID;
if (sessionUUID != _lastOwnerSessionUUID) {
AvatarSharedPointer matchingAvatarData = matchingOrNewAvatar(sessionUUID, mixerWeakPointer);
AvatarSharedPointer avatar = _avatarHash.value(sessionUUID);
if (!avatar) {
avatar = addAvatar(sessionUUID, mixerWeakPointer);
}
// have the matching (or new) avatar parse the data from the packet
bytesRead += matchingAvatarData->parseDataAtOffset(datagram, bytesRead);
bytesRead += avatar->parseDataAtOffset(datagram, bytesRead);
} else {
// create a dummy AvatarData class to throw this data on the ground
AvatarData dummyData;
@ -145,24 +105,24 @@ void AvatarHashMap::processAvatarIdentityPacket(const QByteArray &packet, const
identityStream >> sessionUUID >> faceMeshURL >> skeletonURL >> attachmentData >> displayName;
// mesh URL for a UUID, find avatar in our list
AvatarSharedPointer matchingAvatar = matchingOrNewAvatar(sessionUUID, mixerWeakPointer);
if (matchingAvatar) {
if (matchingAvatar->getFaceModelURL() != faceMeshURL) {
matchingAvatar->setFaceModelURL(faceMeshURL);
}
if (matchingAvatar->getSkeletonModelURL() != skeletonURL) {
matchingAvatar->setSkeletonModelURL(skeletonURL);
}
if (matchingAvatar->getAttachmentData() != attachmentData) {
matchingAvatar->setAttachmentData(attachmentData);
}
if (matchingAvatar->getDisplayName() != displayName) {
matchingAvatar->setDisplayName(displayName);
}
AvatarSharedPointer avatar = _avatarHash.value(sessionUUID);
if (!avatar) {
avatar = addAvatar(sessionUUID, mixerWeakPointer);
}
if (avatar->getFaceModelURL() != faceMeshURL) {
avatar->setFaceModelURL(faceMeshURL);
}
if (avatar->getSkeletonModelURL() != skeletonURL) {
avatar->setSkeletonModelURL(skeletonURL);
}
if (avatar->getAttachmentData() != attachmentData) {
avatar->setAttachmentData(attachmentData);
}
if (avatar->getDisplayName() != displayName) {
avatar->setDisplayName(displayName);
}
}
}
@ -171,24 +131,25 @@ void AvatarHashMap::processAvatarBillboardPacket(const QByteArray& packet, const
int headerSize = numBytesForPacketHeader(packet);
QUuid sessionUUID = QUuid::fromRfc4122(QByteArray::fromRawData(packet.constData() + headerSize, NUM_BYTES_RFC4122_UUID));
AvatarSharedPointer matchingAvatar = matchingOrNewAvatar(sessionUUID, mixerWeakPointer);
if (matchingAvatar) {
QByteArray billboard = packet.mid(headerSize + NUM_BYTES_RFC4122_UUID);
if (matchingAvatar->getBillboard() != billboard) {
matchingAvatar->setBillboard(billboard);
}
AvatarSharedPointer avatar = _avatarHash.value(sessionUUID);
if (!avatar) {
avatar = addAvatar(sessionUUID, mixerWeakPointer);
}
QByteArray billboard = packet.mid(headerSize + NUM_BYTES_RFC4122_UUID);
if (avatar->getBillboard() != billboard) {
avatar->setBillboard(billboard);
}
}
void AvatarHashMap::processKillAvatar(const QByteArray& datagram) {
// read the node id
QUuid sessionUUID = QUuid::fromRfc4122(datagram.mid(numBytesForPacketHeader(datagram), NUM_BYTES_RFC4122_UUID));
// remove the avatar with that UUID from our hash, if it exists
AvatarHash::iterator matchedAvatar = _avatarHash.find(sessionUUID);
if (matchedAvatar != _avatarHash.end()) {
erase(matchedAvatar);
}
removeAvatar(sessionUUID);
}
void AvatarHashMap::removeAvatar(const QUuid& sessionUUID) {
_avatarHash.remove(sessionUUID);
}
void AvatarHashMap::sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID) {

View file

@ -36,28 +36,26 @@ public:
public slots:
void processAvatarMixerDatagram(const QByteArray& datagram, const QWeakPointer<Node>& mixerWeakPointer);
bool containsAvatarWithDisplayName(const QString& displayName);
bool isAvatarInRange(const glm::vec3 & position, const float range);
AvatarWeakPointer avatarWithDisplayName(const QString& displayname);
private slots:
void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID);
protected:
AvatarHashMap();
virtual AvatarHash::iterator erase(const AvatarHash::iterator& iterator);
bool shouldKillAvatar(const AvatarSharedPointer& sharedAvatar);
virtual AvatarSharedPointer newSharedAvatar();
AvatarSharedPointer matchingOrNewAvatar(const QUuid& nodeUUID, const QWeakPointer<Node>& mixerWeakPointer);
virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer);
virtual void removeAvatar(const QUuid& sessionUUID);
AvatarHash _avatarHash;
private:
void processAvatarDataPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
void processAvatarIdentityPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
void processAvatarBillboardPacket(const QByteArray& packet, const QWeakPointer<Node>& mixerWeakPointer);
void processKillAvatar(const QByteArray& datagram);
AvatarHash _avatarHash;
QUuid _lastOwnerSessionUUID;
};

View file

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

View file

@ -39,6 +39,7 @@
#include "RenderableWebEntityItem.h"
#include "RenderableZoneEntityItem.h"
#include "RenderableLineEntityItem.h"
#include "RenderablePolyVoxEntityItem.h"
#include "EntitiesRendererLogging.h"
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
@ -65,6 +66,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(Line, RenderableLineEntityItem::factory)
REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyVox, RenderablePolyVoxEntityItem::factory)
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID;
_currentClickingOnEntityID = UNKNOWN_ENTITY_ID;
@ -113,7 +115,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() {
@ -138,7 +139,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);
}
@ -190,7 +191,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
}
@ -324,7 +325,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
@ -332,7 +333,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();
}
@ -517,12 +518,12 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode,
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) {
@ -532,23 +533,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();
@ -615,7 +616,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");
@ -674,7 +675,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();
@ -686,7 +687,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()) {
@ -696,17 +697,17 @@ 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);
}
}
}
@ -835,7 +836,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);
@ -873,6 +874,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) {
@ -1101,20 +1103,23 @@ 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;
}
QUuid simulatorID = entity->getSimulatorID();
if (simulatorID.isNull()) {
// Can be null if it has never moved since being created or coming out of persistence.
// However, for there to be a collission, one of the two objects must be moving.
const EntityItemID& otherID = (id == collision.idA) ? collision.idB : collision.idA;
EntityItemPointer otherEntity = entityTree->findEntityByEntityItemID(otherID);
if (!otherEntity) {
return;
}
simulatorID = otherEntity->getSimulatorID();
}
if (simulatorID.isNull() || (simulatorID != myNodeID)) {
return; // Only one injector per simulation, please.
}
@ -1187,6 +1192,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;
@ -1196,6 +1202,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;

View file

@ -62,9 +62,9 @@ public:
RenderArgs::RenderSide renderSide = RenderArgs::MONO,
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE);
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();
@ -107,11 +107,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);
@ -130,7 +130,7 @@ private:
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);
@ -147,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);
@ -173,7 +173,7 @@ private:
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
bool _hasPreviousZone = false;
const ZoneEntityItem* _bestZone;
std::shared_ptr<ZoneEntityItem> _bestZone;
float _bestZoneVolume;
glm::vec3 _previousKeyLightColor;

View file

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

View file

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

View file

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

View file

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

View file

@ -18,8 +18,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) {
@ -37,5 +37,6 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
glm::vec3& p2 = dimensions;
DependencyManager::get<DeferredLightingEffect>()->renderLine(p1, p2, lineColor, lineColor);
glPopMatrix();
RenderableDebugableEntityItem::render(this, args);
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,336 @@
//
// RenderablePolyVoxEntityItem.cpp
// libraries/entities-renderer/src/
//
// Created by Seth Alves on 5/19/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QByteArray>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/string_cast.hpp>
#include <gpu/GPUConfig.h>
#include <DeferredLightingEffect.h>
#include <Model.h>
#include <PerfStat.h>
#include <PolyVoxCore/CubicSurfaceExtractorWithNormals.h>
#include <PolyVoxCore/MarchingCubesSurfaceExtractor.h>
#include <PolyVoxCore/SurfaceMesh.h>
#include <PolyVoxCore/SimpleVolume.h>
#include <PolyVoxCore/Raycast.h>
#include <PolyVoxCore/Material.h>
#include "model/Geometry.h"
#include "gpu/GLBackend.h"
#include "EntityTreeRenderer.h"
#include "RenderablePolyVoxEntityItem.h"
EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderablePolyVoxEntityItem(entityID, properties));
}
RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() {
delete _volData;
}
void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
if (_volData && voxelVolumeSize == _voxelVolumeSize) {
return;
}
qDebug() << "resetting voxel-space size";
PolyVoxEntityItem::setVoxelVolumeSize(voxelVolumeSize);
if (_volData) {
delete _volData;
}
PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize[0] - 1, // -1 because these corners are inclusive
_voxelVolumeSize[1] - 1,
_voxelVolumeSize[2] - 1);
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
}
void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
if (voxelData == _voxelData) {
return;
}
PolyVoxEntityItem::setVoxelData(voxelData);
decompressVolumeData();
}
glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const {
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
glm::mat4 scaled = glm::scale(glm::mat4(), scale);
glm::mat4 centerToCorner = glm::translate(scaled, _voxelVolumeSize / -2.0f);
glm::mat4 rotation = glm::mat4_cast(_rotation);
glm::mat4 translation = glm::translate(getCenter());
return translation * rotation * centerToCorner;
}
glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const {
glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix());
return worldToModelMatrix;
}
void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) {
// This three-level for loop iterates over every voxel in the volume
for (int z = 0; z < _volData->getDepth(); z++) {
for (int y = 0; y < _volData->getHeight(); y++) {
for (int x = 0; x < _volData->getWidth(); x++) {
// Store our current position as a vector...
glm::vec3 pos(x, y, z);
// And compute how far the current position is from the center of the volume
float fDistToCenter = glm::distance(pos, center);
// If the current voxel is less than 'radius' units from the center then we make it solid.
if (fDistToCenter <= radius) {
_volData->setVoxelAt(x, y, z, toValue);
}
}
}
}
compressVolumeData();
_needsModelReload = true;
}
void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) {
// glm::vec3 centerVoxelCoords = worldToVoxelCoordinates(centerWorldCoords);
glm::vec4 centerVoxelCoords = worldToVoxelMatrix() * glm::vec4(centerWorldCoords, 1.0f);
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
float scaleY = scale[0];
float radiusVoxelCoords = radiusWorldCoords / scaleY;
setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue);
}
void RenderablePolyVoxEntityItem::getModel() {
if (!_volData) {
// this will cause the allocation of _volData
setVoxelVolumeSize(_voxelVolumeSize);
}
// A mesh object to hold the result of surface extraction
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> polyVoxMesh;
switch (_voxelSurfaceStyle) {
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: {
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
surfaceExtractor.execute();
break;
}
case PolyVoxEntityItem::SURFACE_CUBIC: {
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
surfaceExtractor.execute();
break;
}
}
// convert PolyVox mesh to a Sam mesh
model::Mesh* mesh = new model::Mesh();
model::MeshPointer meshPtr(mesh);
const std::vector<uint32_t>& vecIndices = polyVoxMesh.getIndices();
auto indexBuffer = new gpu::Buffer(vecIndices.size() * sizeof(uint32_t), (gpu::Byte*)vecIndices.data());
auto indexBufferPtr = gpu::BufferPointer(indexBuffer);
mesh->setIndexBuffer(gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW)));
const std::vector<PolyVox::PositionMaterialNormal>& vecVertices = polyVoxMesh.getVertices();
auto vertexBuffer = new gpu::Buffer(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal),
(gpu::Byte*)vecVertices.data());
auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer);
mesh->setVertexBuffer(gpu::BufferView(vertexBufferPtr,
0,
vertexBufferPtr->getSize() - sizeof(float) * 3,
sizeof(PolyVox::PositionMaterialNormal),
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
mesh->addAttribute(gpu::Stream::NORMAL,
gpu::BufferView(vertexBufferPtr,
sizeof(float) * 3,
vertexBufferPtr->getSize() - sizeof(float) * 3,
sizeof(PolyVox::PositionMaterialNormal),
gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)));
// auto normalAttrib = mesh->getAttributeBuffer(gpu::Stream::NORMAL);
// for (auto normal = normalAttrib.begin<glm::vec3>(); normal != normalAttrib.end<glm::vec3>(); normal++) {
// (*normal) = -(*normal);
// }
qDebug() << "---- vecIndices.size() =" << vecIndices.size();
qDebug() << "---- vecVertices.size() =" << vecVertices.size();
_modelGeometry.setMesh(meshPtr);
_needsModelReload = false;
}
void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render");
assert(getType() == EntityTypes::PolyVox);
if (_needsModelReload) {
getModel();
}
glm::vec3 position = getPosition();
glm::vec3 dimensions = getDimensions();
glm::vec3 scale = dimensions / _voxelVolumeSize;
glm::vec3 center = getCenter();
glm::quat rotation = getRotation();
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glm::vec3 positionToCenter = center - position;
// make the rendered voxel volume be centered on the entity's position
positionToCenter -= _dimensions * glm::vec3(0.5f,0.5f,0.5f);
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
glScalef(scale.x, scale.y, scale.z);
auto mesh = _modelGeometry.getMesh();
gpu::Batch batch;
batch.setInputFormat(mesh->getVertexFormat());
batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer());
batch.setInputBuffer(gpu::Stream::NORMAL,
mesh->getVertexBuffer()._buffer,
sizeof(float) * 3,
mesh->getVertexBuffer()._stride);
batch.setIndexBuffer(gpu::UINT32, mesh->getIndexBuffer()._buffer, 0);
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
gpu::GLBackend::renderBatch(batch);
glPopMatrix();
RenderableDebugableEntityItem::render(this, args);
}
class RaycastFunctor
{
public:
RaycastFunctor() : _result(glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)) { }
bool operator()(PolyVox::SimpleVolume<unsigned char>::Sampler& sampler)
{
if (sampler.getVoxel() == 0) {
return true; // keep raycasting
}
PolyVox::Vector3DInt32 positionIndex = sampler.getPosition();
_result = glm::vec4(positionIndex.getX(), positionIndex.getY(), positionIndex.getZ(), 1.0f);
return false;
}
glm::vec4 _result;
};
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin,
const glm::vec3& direction,
bool& keepSearching,
OctreeElement*& element,
float& distance, BoxFace& face,
void** intersectedObject,
bool precisionPicking) const
{
if (_needsModelReload || !precisionPicking) {
// just intersect with bounding box
return true;
}
glm::mat4 wtvMatrix = worldToVoxelMatrix();
glm::vec3 farPoint = origin + direction;
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f);
glm::vec4 directionInVoxel = farInVoxel - originInVoxel;
PolyVox::Vector3DFloat start(originInVoxel[0], originInVoxel[1], originInVoxel[2]);
PolyVox::Vector3DFloat pvDirection(directionInVoxel[0], directionInVoxel[1], directionInVoxel[2]);
pvDirection.normalise();
// the PolyVox ray intersection code requires a near and far point.
glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units
float distanceToEntity = glm::distance(origin, _position);
float largestDimension = glm::max(_dimensions[0], _dimensions[1], _dimensions[2]);
// set ray cast length to long enough to cover all of the voxel space
pvDirection *= (distanceToEntity + largestDimension) / glm::min(scale[0], scale[1], scale[2]);
PolyVox::RaycastResult raycastResult;
RaycastFunctor callback;
raycastResult = PolyVox::raycastWithDirection(_volData, start, pvDirection, callback);
if (raycastResult == PolyVox::RaycastResults::Completed) {
// the ray completed its path -- nothing was hit.
return false;
}
glm::vec4 intersectedWorldPosition = voxelToWorldMatrix() * callback._result;
distance = glm::distance(glm::vec3(intersectedWorldPosition), origin);
face = BoxFace::MIN_X_FACE; // XXX
return true;
}
// compress the data in _volData and save the results. The compressed form is used during
// saves to disk and for transmission over the wire
void RenderablePolyVoxEntityItem::compressVolumeData() {
int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth();
QByteArray uncompressedData = QByteArray(rawSize, '\0');
for (int z = 0; z < _volData->getDepth(); z++) {
for (int y = 0; y < _volData->getHeight(); y++) {
for (int x = 0; x < _volData->getWidth(); x++) {
uint8_t uVoxelValue = _volData->getVoxelAt(x, y, z);
int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x;
uncompressedData[uncompressedIndex] = uVoxelValue;
}
}
}
QByteArray newVoxelData = qCompress(uncompressedData, 9);
// HACK -- until we have a way to allow for properties larger than MTU, don't update.
if (newVoxelData.length() < 1200) {
_voxelData = newVoxelData;
qDebug() << "-------------- voxel compresss --------------";
qDebug() << "raw-size =" << rawSize << " compressed-size =" << newVoxelData.size();
} else {
qDebug() << "voxel data too large, reverting change.";
// revert
decompressVolumeData();
}
}
// take compressed data and decompreess it into _volData.
void RenderablePolyVoxEntityItem::decompressVolumeData() {
int rawSize = _volData->getDepth() * _volData->getHeight() * _volData->getWidth();
QByteArray uncompressedData = QByteArray(rawSize, '\0');
uncompressedData = qUncompress(_voxelData);
for (int z = 0; z < _volData->getDepth(); z++) {
for (int y = 0; y < _volData->getHeight(); y++) {
for (int x = 0; x < _volData->getWidth(); x++) {
int uncompressedIndex = z * _volData->getHeight() * _volData->getWidth() + y * _volData->getWidth() + x;
_volData->setVoxelAt(x, y, z, uncompressedData[uncompressedIndex]);
}
}
}
_needsModelReload = true;
qDebug() << "--------------- voxel decompress ---------------";
qDebug() << "raw-size =" << rawSize << " compressed-size =" << _voxelData.size();
}

View file

@ -0,0 +1,68 @@
//
// RenderablePolyVoxEntityItem.h
// libraries/entities-renderer/src/
//
// Created by Seth Alves on 5/19/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RenderablePolyVoxEntityItem_h
#define hifi_RenderablePolyVoxEntityItem_h
#include <PolyVoxCore/SimpleVolume.h>
#include "PolyVoxEntityItem.h"
#include "RenderableDebugableEntityItem.h"
class RenderablePolyVoxEntityItem : public PolyVoxEntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
PolyVoxEntityItem(entityItemID, properties) { }
virtual ~RenderablePolyVoxEntityItem();
virtual void somethingChangedNotification() {
// This gets called from EnityItem::readEntityDataFromBuffer every time a packet describing
// this entity comes from the entity-server. It gets called even if nothing has actually changed
// (see the comment in EntityItem.cpp). If that gets fixed, this could be used to know if we
// need to redo the voxel data.
// _needsModelReload = true;
}
void render(RenderArgs* args);
virtual bool supportsDetailedRayIntersection() const { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject, bool precisionPicking) const;
void getModel();
virtual void setVoxelData(QByteArray voxelData);
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
glm::mat4 voxelToWorldMatrix() const;
glm::mat4 worldToVoxelMatrix() const;
// coords are in voxel-volume space
virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue);
// coords are in world-space
virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue);
private:
void compressVolumeData();
void decompressVolumeData();
PolyVox::SimpleVolume<uint8_t>* _volData = nullptr;
model::Geometry _modelGeometry;
bool _needsModelReload = true;
};
#endif // hifi_RenderablePolyVoxEntityItem_h

View file

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

View file

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

View file

@ -23,8 +23,8 @@
const int FIXED_FONT_POINT_SIZE = 40;
EntityItem* RenderableTextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return new RenderableTextEntityItem(entityID, properties);
EntityItemPointer RenderableTextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new RenderableTextEntityItem(entityID, properties));
}
void RenderableTextEntityItem::render(RenderArgs* args) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -183,9 +183,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
QByteArray encodedPropertyFlags;
int propertyCount = 0;
successIDFits = packetData->appendValue(encodedID);
successIDFits = packetData->appendRawData(encodedID);
if (successIDFits) {
successTypeFits = packetData->appendValue(encodedType);
successTypeFits = packetData->appendRawData(encodedType);
}
if (successTypeFits) {
successCreatedFits = packetData->appendValue(_created);
@ -194,17 +194,17 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
successLastEditedFits = packetData->appendValue(lastEdited);
}
if (successLastEditedFits) {
successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
successLastUpdatedFits = packetData->appendRawData(encodedUpdateDelta);
}
if (successLastUpdatedFits) {
successLastSimulatedFits = packetData->appendValue(encodedSimulatedDelta);
successLastSimulatedFits = packetData->appendRawData(encodedSimulatedDelta);
}
if (successLastSimulatedFits) {
propertyFlagsOffset = packetData->getUncompressedByteOffset();
encodedPropertyFlags = propertyFlags;
oldPropertyFlagsLength = encodedPropertyFlags.length();
successPropertyFlagsFits = packetData->appendValue(encodedPropertyFlags);
successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags);
}
bool headerFits = successIDFits && successTypeFits && successCreatedFits && successLastEditedFits
@ -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 = _position;
glm::quat saveRotation = _rotation;
// 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 = _position;
glm::quat saveRotation = _rotation;
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
_position = savePosition;
_rotation = saveRotation;
// _velocity = saveVelocity;
// _angularVelocity = saveAngularVelocity;
// _gravity = saveGravity;
// _acceleration = saveAcceleration;
_velocity = saveVelocity;
_angularVelocity = saveAngularVelocity;
_dirtyFlags &= ~(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES);
}
return bytesRead;
@ -652,6 +652,7 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s
// lastEdited
quint64 lastEditedInLocalTime;
memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime));
assert(lastEditedInLocalTime > 0);
quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew;
memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime));
#ifdef WANT_DEBUG
@ -948,18 +949,18 @@ 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 (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;
}
}
@ -972,14 +973,6 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
timestamp = now;
}
_created = timestamp;
timestamp = properties.getLastEdited();
if (timestamp > now) {
timestamp = now;
} else if (timestamp < _created) {
timestamp = _created;
}
_lastEdited = timestamp;
}
return somethingChanged;

View file

@ -26,6 +26,7 @@
#include "ParticleEffectEntityItem.h"
#include "TextEntityItem.h"
#include "ZoneEntityItem.h"
#include "PolyVoxEntityItem.h"
AtmospherePropertyGroup EntityItemProperties::_staticAtmosphere;
SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
@ -87,10 +88,14 @@ CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR),
CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY),
CONSTRUCT_PROPERTY(keyLightAmbientIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY),
CONSTRUCT_PROPERTY(keyLightDirection, ZoneEntityItem::DEFAULT_KEYLIGHT_DIRECTION),
CONSTRUCT_PROPERTY(voxelVolumeSize, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE),
CONSTRUCT_PROPERTY(voxelData, PolyVoxEntityItem::DEFAULT_VOXEL_DATA),
CONSTRUCT_PROPERTY(voxelSurfaceStyle, PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE),
CONSTRUCT_PROPERTY(name, ENTITY_ITEM_DEFAULT_NAME),
CONSTRUCT_PROPERTY(backgroundMode, BACKGROUND_MODE_INHERIT),
CONSTRUCT_PROPERTY(sourceUrl, ""),
_id(UNKNOWN_ENTITY_ID),
_idSet(false),
_lastEdited(0),
@ -336,6 +341,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, keyLightDirection);
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_DATA, voxelData);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle);
changedProperties += _stage.getChangedProperties();
changedProperties += _atmosphere.getChangedProperties();
@ -418,6 +426,10 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelVolumeSize);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelData);
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelSurfaceStyle);
// Sitting properties support
if (!skipDefaults) {
@ -523,7 +535,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightDirection, glmVec3, setKeyLightDirection);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle);
_stage.copyFromScriptValue(object, _defaultSettings);
_atmosphere.copyFromScriptValue(object, _defaultSettings);
_skybox.copyFromScriptValue(object, _defaultSettings);
@ -619,23 +635,23 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
quint64 lastEdited = properties.getLastEdited();
bool successLastEditedFits = packetData->appendValue(lastEdited);
bool successIDFits = packetData->appendValue(encodedID);
bool successIDFits = packetData->appendRawData(encodedID);
if (successIDFits) {
successIDFits = packetData->appendValue(encodedToken);
successIDFits = packetData->appendRawData(encodedToken);
}
bool successTypeFits = packetData->appendValue(encodedType);
bool successTypeFits = packetData->appendRawData(encodedType);
// NOTE: We intentionally do not send "created" times in edit messages. This is because:
// 1) if the edit is to an existing entity, the created time can not be changed
// 2) if the edit is to a new entity, the created time is the last edited time
// TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
bool successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
bool successLastUpdatedFits = packetData->appendRawData(encodedUpdateDelta);
int propertyFlagsOffset = packetData->getUncompressedByteOffset();
QByteArray encodedPropertyFlags = propertyFlags;
int oldPropertyFlagsLength = encodedPropertyFlags.length();
bool successPropertyFlagsFits = packetData->appendValue(encodedPropertyFlags);
bool successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags);
int propertyCount = 0;
bool headerFits = successIDFits && successTypeFits && successLastEditedFits
@ -740,6 +756,12 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
_staticSkybox.setProperties(properties);
_staticSkybox.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
}
if (properties.getType() == EntityTypes::PolyVox) {
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, properties.getVoxelVolumeSize());
APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, properties.getVoxelData());
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, properties.getVoxelSurfaceStyle());
}
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
@ -974,11 +996,17 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
properties.getAtmosphere().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
}
if (properties.getType() == EntityTypes::PolyVox) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_VOLUME_SIZE, glm::vec3, setVoxelVolumeSize);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_DATA, QByteArray, setVoxelData);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
}
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
return valid;
}
@ -1079,6 +1107,10 @@ void EntityItemProperties::markAllChanged() {
_skybox.markAllChanged();
_sourceUrlChanged = true;
_voxelVolumeSizeChanged = true;
_voxelDataChanged = true;
_voxelSurfaceStyleChanged = true;
}
/// The maximum bounding cube for the entity, independent of it's rotation.

View file

@ -54,6 +54,7 @@ class EntityItemProperties {
friend class ZoneEntityItem; // TODO: consider removing this friend relationship and use public methods
friend class WebEntityItem; // TODO: consider removing this friend relationship and use public methods
friend class LineEntityItem; // TODO: consider removing this friend relationship and use public methods
friend class PolyVoxEntityItem; // TODO: consider removing this friend relationship and use public methods
public:
EntityItemProperties();
virtual ~EntityItemProperties();
@ -135,6 +136,9 @@ public:
DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
DEFINE_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float);
DEFINE_PROPERTY_REF(PROP_KEYLIGHT_DIRECTION, KeyLightDirection, keyLightDirection, glm::vec3);
DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3);
DEFINE_PROPERTY_REF(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray);
DEFINE_PROPERTY_REF(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t);
DEFINE_PROPERTY_REF(PROP_NAME, Name, name, QString);
DEFINE_PROPERTY_REF_ENUM(PROP_BACKGROUND_MODE, BackgroundMode, backgroundMode, BackgroundMode);
DEFINE_PROPERTY_GROUP(Stage, stage, StagePropertyGroup);
@ -189,6 +193,8 @@ public:
QString getSimulatorIDAsString() const { return _simulatorID.toString().mid(1,36).toUpper(); }
void setVoxelDataDirty() { _voxelDataChanged = true; }
private:
QUuid _id;
bool _idSet;
@ -219,7 +225,6 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP
inline void EntityItemProperties::setPosition(const glm::vec3& value)
{ _position = glm::clamp(value, 0.0f, (float)TREE_SCALE); _positionChanged = true; }
inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
debug << "EntityItemProperties[" << "\n";
@ -281,6 +286,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelData, voxelData, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelSurfaceStyle, voxelSurfaceStyle, "");
properties.getStage().debugDump();
properties.getAtmosphere().debugDump();

View file

@ -32,7 +32,7 @@
#define READ_ENTITY_PROPERTY(P,T,S) \
if (propertyFlags.getHasProperty(P)) { \
T fromBuffer; \
int bytes = OctreePacketData::uppackDataFromBytes(dataAt, fromBuffer); \
int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
dataAt += bytes; \
bytesRead += bytes; \
if (overwriteLocalData) { \
@ -49,7 +49,7 @@
#define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \
if (propertyFlags.getHasProperty(P)) { \
T fromBuffer; \
int bytes = OctreePacketData::uppackDataFromBytes(dataAt, fromBuffer); \
int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
dataAt += bytes; \
processedBytes += bytes; \
properties.O(fromBuffer); \
@ -91,10 +91,18 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScri
inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, quint32 v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { return QScriptValue(v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { return xColorToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; }
inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
QByteArray b64 = v.toBase64();
return QScriptValue(QString(b64));
}
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
QScriptValue groupProperties = properties.property(#g); \
@ -129,6 +137,16 @@ inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { re
inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); }
inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
inline QByteArray QByteArray_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;
QString b64 = v.toVariant().toString().trimmed();
return QByteArray::fromBase64(b64.toUtf8());
}
inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");

View file

@ -110,6 +110,10 @@ enum EntityPropertyList {
PROP_RESTITUTION,
PROP_FRICTION,
PROP_VOXEL_VOLUME_SIZE,
PROP_VOXEL_DATA,
PROP_VOXEL_SURFACE_STYLE,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -17,6 +17,7 @@
#include "ModelEntityItem.h"
#include "ZoneEntityItem.h"
#include "EntitiesLogging.h"
#include "PolyVoxEntityItem.h"
EntityScriptingInterface::EntityScriptingInterface() :
@ -78,11 +79,12 @@ 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.
bidForSimulationOwnership(propertiesWithSimID);
entity->setSimulatorID(propertiesWithSimID.getSimulatorID()); // and make note of it now, so we can act on it right away.
} else {
qCDebug(entities) << "script failed to add new Entity to local Octree";
success = false;
@ -102,7 +104,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 +140,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 +164,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 +186,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 +208,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 +224,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 +251,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);
@ -380,3 +383,40 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
vec3FromScriptValue(intersection, value.intersection);
}
}
bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) {
if (!_entityTree) {
return false;
}
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
if (!entity) {
qCDebug(entities) << "EntityScriptingInterface::setVoxelSphere no entity with ID" << entityID;
return false;
}
EntityTypes::EntityType entityType = entity->getType();
if (entityType != EntityTypes::PolyVox) {
return false;
}
auto now = usecTimestampNow();
PolyVoxEntityItem* polyVoxEntity = static_cast<PolyVoxEntityItem*>(entity.get());
_entityTree->lockForWrite();
polyVoxEntity->setSphere(center, radius, value);
entity->setLastEdited(now);
entity->setLastBroadcast(now);
_entityTree->unlock();
_entityTree->lockForRead();
EntityItemProperties properties = entity->getProperties();
_entityTree->unlock();
properties.setVoxelDataDirty();
properties.setLastEdited(now);
queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
return true;
}

View file

@ -39,7 +39,7 @@ public:
float distance;
BoxFace face;
glm::vec3 intersection;
EntityItem* entity;
EntityItemPointer entity;
};
Q_DECLARE_METATYPE(RayToEntityIntersectionResult)
@ -117,10 +117,13 @@ public slots:
Q_INVOKABLE void setSendPhysicsUpdates(bool value);
Q_INVOKABLE bool getSendPhysicsUpdates() const;
Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);
Q_INVOKABLE void dumpTree() const;
signals:
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
void canAdjustLocksChanged(bool canAdjustLocks);
void canRezChanged(bool canRez);

View file

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

View file

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

View file

@ -75,7 +75,7 @@ bool EntityTree::handlesEditPacketType(PacketType packetType) const {
}
/// Adds a new entity item to the tree
void EntityTree::postAddEntity(EntityItem* entity) {
void EntityTree::postAddEntity(EntityItemPointer entity) {
assert(entity);
// check to see if we need to simulate this entity..
if (_simulation) {
@ -84,6 +84,7 @@ void EntityTree::postAddEntity(EntityItem* entity) {
_simulation->unlock();
}
_isDirty = true;
maybeNotifyNewCollisionSoundURL("", entity->getCollisionSoundURL());
emit addingEntity(entity->getEntityItemID());
}
@ -94,7 +95,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 +104,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 +114,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;
@ -184,6 +185,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
// else client accepts what the server says
QString entityScriptBefore = entity->getScript();
QString collisionSoundURLBefore = entity->getCollisionSoundURL();
uint32_t preFlags = entity->getDirtyFlags();
UpdateEntityOperator theOperator(this, containingElement, entity, properties);
recurseTreeWithOperator(&theOperator);
@ -206,8 +208,9 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
QString entityScriptAfter = entity->getScript();
if (entityScriptBefore != entityScriptAfter) {
emitEntityScriptChanging(entity->getEntityItemID()); // the entity script has changed
}
}
}
maybeNotifyNewCollisionSoundURL(collisionSoundURLBefore, entity->getCollisionSoundURL());
}
// TODO: this final containingElement check should eventually be removed (or wrapped in an #ifdef DEBUG).
containingElement = getContainingElement(entity->getEntityItemID());
@ -220,8 +223,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.
@ -266,6 +269,11 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem
void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) {
emit entityScriptChanging(entityItemID);
}
void EntityTree::maybeNotifyNewCollisionSoundURL(const QString& previousCollisionSoundURL, const QString& nextCollisionSoundURL) {
if (!nextCollisionSoundURL.isEmpty() && (nextCollisionSoundURL != previousCollisionSoundURL)) {
emit newCollisionSoundURL(QUrl(nextCollisionSoundURL));
}
}
void EntityTree::setSimulation(EntitySimulation* simulation) {
if (simulation) {
@ -291,7 +299,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 +336,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 +370,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 +382,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 +395,7 @@ public:
glm::vec3 position;
float targetRadius;
bool found;
const EntityItem* closestEntity;
EntityItemPointer closestEntity;
float closestEntityDistance;
};
@ -402,7 +409,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 +435,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 +448,7 @@ class FindAllNearPointArgs {
public:
glm::vec3 position;
float targetRadius;
QVector<const EntityItem*> entities;
QVector<EntityItemPointer> entities;
};
@ -462,8 +469,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 +485,7 @@ public:
}
AACube _cube;
QVector<EntityItem*> _foundEntities;
QVector<EntityItemPointer> _foundEntities;
};
bool EntityTree::findInCubeOperation(OctreeElement* element, void* extraData) {
@ -492,7 +499,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 +514,7 @@ public:
}
AABox _box;
QVector<EntityItem*> _foundEntities;
QVector<EntityItemPointer> _foundEntities;
};
bool EntityTree::findInBoxOperation(OctreeElement* element, void* extraData) {
@ -521,7 +528,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 +536,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 +578,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 +595,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 +611,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 +659,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 +679,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 +1012,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 +1064,7 @@ bool EntityTree::readFromMap(QVariantMap& map) {
entityItemID = EntityItemID(QUuid::createUuid());
}
EntityItem* entity = addEntity(entityItemID, properties);
EntityItemPointer entity = addEntity(entityItemID, properties);
if (!entity) {
qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType();
}

View file

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

View file

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

View file

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

View file

@ -27,6 +27,7 @@
#include "WebEntityItem.h"
#include "ZoneEntityItem.h"
#include "LineEntityItem.h"
#include "PolyVoxEntityItem.h"
QMap<EntityTypes::EntityType, QString> EntityTypes::_typeToNameMap;
QMap<QString, EntityTypes::EntityType> EntityTypes::_nameToTypeMap;
@ -45,6 +46,7 @@ REGISTER_ENTITY_TYPE(Text)
REGISTER_ENTITY_TYPE(ParticleEffect)
REGISTER_ENTITY_TYPE(Zone)
REGISTER_ENTITY_TYPE(Line)
REGISTER_ENTITY_TYPE(PolyVox)
const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
QMap<EntityType, QString>::iterator matchedTypeName = _typeToNameMap.find(entityType);
@ -76,9 +78,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 +93,7 @@ EntityItem* EntityTypes::constructEntityItem(EntityType entityType, const Entity
return newEntityItem;
}
EntityItem* EntityTypes::constructEntityItem(const unsigned char* data, int bytesToRead,
EntityItemPointer EntityTypes::constructEntityItem(const unsigned char* data, int bytesToRead,
ReadBitstreamToTreeParams& args) {
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU) {

View file

@ -20,11 +20,17 @@
#include <OctreeRenderer.h> // for RenderArgs
class EntityItem;
typedef std::shared_ptr<EntityItem> EntityItemPointer;
inline uint qHash(const EntityItemPointer& a, uint seed) {
return qHash(a.get(), seed);
}
class EntityItemID;
class EntityItemProperties;
class ReadBitstreamToTreeParams;
typedef EntityItem* (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties);
typedef EntityItemPointer (*EntityTypeFactory)(const EntityItemID& entityID, const EntityItemProperties& properties);
class EntityTypes {
public:
@ -39,14 +45,15 @@ public:
Zone,
Web,
Line,
LAST = Line
PolyVox,
LAST = PolyVox
} EntityType;
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 +66,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 +74,7 @@ private:
/// an element to the EntityType enum with your name. But unlike REGISTER_ENTITY_TYPE, your class can be named anything
/// so long as you provide a static method passed to the macro, that takes an EnityItemID, and EntityItemProperties and
/// returns a newly constructed (heap allocated) instance of your type. e.g. The following prototype:
// static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
// static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
#define REGISTER_ENTITY_TYPE_WITH_FACTORY(x,y) static bool x##Registration = \
EntityTypes::registerEntityType(EntityTypes::x, #x, y); \
if (!x##Registration) { \

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,117 @@
//
// PolyVoxEntityItem.cpp
// libraries/entities/src
//
// Created by Seth Alves on 5/11/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QByteArray>
#include <QDebug>
#include <ByteCountCoding.h>
#include "PolyVoxEntityItem.h"
#include "EntityTree.h"
#include "EntitiesLogging.h"
#include "EntityTreeElement.h"
const glm::vec3 PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE = glm::vec3(32, 32, 32);
const QByteArray PolyVoxEntityItem::DEFAULT_VOXEL_DATA(qCompress(QByteArray(0), 9));
const PolyVoxEntityItem::PolyVoxSurfaceStyle PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE =
PolyVoxEntityItem::SURFACE_MARCHING_CUBES;
EntityItemPointer PolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return EntityItemPointer(new PolyVoxEntityItem(entityID, properties));
}
PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID),
_voxelVolumeSize(PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE),
_voxelData(PolyVoxEntityItem::DEFAULT_VOXEL_DATA),
_voxelSurfaceStyle(PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE)
{
_type = EntityTypes::PolyVox;
_created = properties.getCreated();
setProperties(properties);
}
EntityItemProperties PolyVoxEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelData, getVoxelData);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelSurfaceStyle, getVoxelSurfaceStyle);
return properties;
}
bool PolyVoxEntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelVolumeSize, setVoxelVolumeSize);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelData, setVoxelData);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelSurfaceStyle, setVoxelSurfaceStyle);
if (somethingChanged) {
bool wantDebug = false;
if (wantDebug) {
uint64_t now = usecTimestampNow();
int elapsed = now - getLastEdited();
qCDebug(entities) << "PolyVoxEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
"now=" << now << " getLastEdited()=" << getLastEdited();
}
setLastEdited(properties._lastEdited);
}
return somethingChanged;
}
int PolyVoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, glm::vec3, setVoxelVolumeSize);
READ_ENTITY_PROPERTY(PROP_VOXEL_DATA, QByteArray, setVoxelData);
READ_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle);
return bytesRead;
}
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
requestedProperties += PROP_VOXEL_VOLUME_SIZE;
requestedProperties += PROP_VOXEL_DATA;
requestedProperties += PROP_VOXEL_SURFACE_STYLE;
return requestedProperties;
}
void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, getVoxelVolumeSize());
APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, getVoxelData());
APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, (uint16_t) getVoxelSurfaceStyle());
}
void PolyVoxEntityItem::debugDump() const {
quint64 now = usecTimestampNow();
qCDebug(entities) << " POLYVOX EntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " position:" << debugTreeVector(_position);
qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions);
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
}

View file

@ -0,0 +1,98 @@
//
// PolyVoxEntityItem.h
// libraries/entities/src
//
// Created by Seth Alves on 5/11/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_PolyVoxEntityItem_h
#define hifi_PolyVoxEntityItem_h
#include "EntityItem.h"
class PolyVoxEntityItem : public EntityItem {
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
ALLOW_INSTANTIATION // This class can be instantiated
// methods for getting/setting all properties of an entity
virtual EntityItemProperties getProperties() const;
virtual bool setProperties(const EntityItemProperties& properties);
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
void setXColor(const xColor& value) {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
}
virtual ShapeType getShapeType() const { return SHAPE_TYPE_POLYVOX; }
// never have a ray intersection pick a PolyVoxEntityItem.
virtual bool supportsDetailedRayIntersection() const { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject, bool precisionPicking) const { return false; }
virtual void debugDump() const;
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { _voxelVolumeSize = voxelVolumeSize; }
virtual const glm::vec3& getVoxelVolumeSize() const { return _voxelVolumeSize; }
virtual void setVoxelData(QByteArray voxelData) { _voxelData = voxelData; }
virtual const QByteArray& getVoxelData() const { return _voxelData; }
enum PolyVoxSurfaceStyle {
SURFACE_MARCHING_CUBES,
SURFACE_CUBIC
};
virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; }
virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) {
_voxelSurfaceStyle = (PolyVoxSurfaceStyle) voxelSurfaceStyle;
}
virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; }
static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE;
static const QByteArray DEFAULT_VOXEL_DATA;
static const PolyVoxSurfaceStyle DEFAULT_VOXEL_SURFACE_STYLE;
// coords are in voxel-volume space
virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) {}
// coords are in world-space
virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue) {}
protected:
rgbColor _color;
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
QByteArray _voxelData;
PolyVoxSurfaceStyle _voxelSurfaceStyle;
};
#endif // hifi_PolyVoxEntityItem_h

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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