mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-08 19:56:48 +02:00
complete migration of Avatar list to AvatarManager
This commit is contained in:
parent
1f95d0c017
commit
2e548fb39c
13 changed files with 282 additions and 292 deletions
|
@ -139,8 +139,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_nudgeStarted(false),
|
_nudgeStarted(false),
|
||||||
_lookingAlongX(false),
|
_lookingAlongX(false),
|
||||||
_lookingAwayFromOrigin(true),
|
_lookingAwayFromOrigin(true),
|
||||||
_lookatTargetAvatar(NULL),
|
|
||||||
_lookatIndicatorScale(1.0f),
|
|
||||||
_chatEntryOn(false),
|
_chatEntryOn(false),
|
||||||
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
|
_audio(&_audioScope, STARTUP_JITTER_SAMPLES),
|
||||||
_enableProcessVoxelsThread(true),
|
_enableProcessVoxelsThread(true),
|
||||||
|
@ -223,9 +221,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
// Voxel File.
|
// Voxel File.
|
||||||
_voxelsFilename = getCmdOption(argc, constArgv, "-i");
|
_voxelsFilename = getCmdOption(argc, constArgv, "-i");
|
||||||
|
|
||||||
// the callback for our instance of NodeList is attachNewHeadToNode
|
|
||||||
nodeList->linkedDataCreateCallback = &attachNewHeadToNode;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WSADATA WsaData;
|
WSADATA WsaData;
|
||||||
int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData);
|
int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData);
|
||||||
|
@ -1146,8 +1141,8 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
||||||
|
|
||||||
// orbit behavior
|
// orbit behavior
|
||||||
if (_mousePressed && !Menu::getInstance()->isVoxelModeActionChecked()) {
|
if (_mousePressed && !Menu::getInstance()->isVoxelModeActionChecked()) {
|
||||||
if (_lookatTargetAvatar) {
|
if (_avatarManager.getLookAtTargetAvatar()) {
|
||||||
_myAvatar.orbit(_lookatTargetAvatar->getPosition(), deltaX, deltaY);
|
_myAvatar.orbit(_avatarManager.getLookAtTargetAvatar()->getPosition(), deltaX, deltaY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_isHoverVoxel) {
|
if (_isHoverVoxel) {
|
||||||
|
@ -1198,7 +1193,7 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_palette.isActive() && (!_isHoverVoxel || _lookatTargetAvatar)) {
|
if (!_palette.isActive() && (!_isHoverVoxel || _avatarManager.getLookAtTargetAvatar())) {
|
||||||
// disable for now
|
// disable for now
|
||||||
// _pieMenu.mousePressEvent(_mouseX, _mouseY);
|
// _pieMenu.mousePressEvent(_mouseX, _mouseY);
|
||||||
}
|
}
|
||||||
|
@ -1422,7 +1417,7 @@ void Application::terminate() {
|
||||||
_settings->sync();
|
_settings->sync();
|
||||||
|
|
||||||
// let the avatar mixer know we're out
|
// let the avatar mixer know we're out
|
||||||
NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
|
_myAvatar.sendKillAvatar();
|
||||||
|
|
||||||
_voxelProcessor.terminate();
|
_voxelProcessor.terminate();
|
||||||
_voxelHideShowThread.terminate();
|
_voxelHideShowThread.terminate();
|
||||||
|
@ -1858,40 +1853,6 @@ const float HEAD_SPHERE_RADIUS = 0.07f;
|
||||||
|
|
||||||
static QUuid DEFAULT_NODE_ID_REF;
|
static QUuid DEFAULT_NODE_ID_REF;
|
||||||
|
|
||||||
void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
|
||||||
glm::vec3& eyePosition) {
|
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()");
|
|
||||||
|
|
||||||
if (!_mousePressed) {
|
|
||||||
_lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
|
||||||
glm::vec3& eyePosition, QUuid& nodeUUID = DEFAULT_NODE_ID_REF) {
|
|
||||||
|
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
|
||||||
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
|
|
||||||
Avatar* avatar = (Avatar*)node->getLinkedData();
|
|
||||||
float distance;
|
|
||||||
|
|
||||||
if (avatar->findRayIntersection(mouseRayOrigin, mouseRayDirection, distance)) {
|
|
||||||
// rescale to compensate for head embiggening
|
|
||||||
eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) *
|
|
||||||
(avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot();
|
|
||||||
|
|
||||||
_lookatIndicatorScale = avatar->getHead().getScale();
|
|
||||||
_lookatOtherPosition = avatar->getHead().getPosition();
|
|
||||||
nodeUUID = avatar->getOwningNode()->getUUID();
|
|
||||||
return avatar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Application::isLookingAtMyAvatar(Avatar* avatar) {
|
bool Application::isLookingAtMyAvatar(Avatar* avatar) {
|
||||||
glm::vec3 theirLookat = avatar->getHead().getLookAtPosition();
|
glm::vec3 theirLookat = avatar->getHead().getLookAtPosition();
|
||||||
glm::vec3 myHeadPosition = _myAvatar.getHead().getPosition();
|
glm::vec3 myHeadPosition = _myAvatar.getHead().getPosition();
|
||||||
|
@ -1902,17 +1863,6 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::renderLookatIndicator(glm::vec3 pointOfInterest) {
|
|
||||||
|
|
||||||
const float DISTANCE_FROM_HEAD_SPHERE = 0.1f * _lookatIndicatorScale;
|
|
||||||
const float INDICATOR_RADIUS = 0.1f * _lookatIndicatorScale;
|
|
||||||
const float YELLOW[] = { 1.0f, 1.0f, 0.0f };
|
|
||||||
const int NUM_SEGMENTS = 30;
|
|
||||||
glm::vec3 haloOrigin(pointOfInterest.x, pointOfInterest.y + DISTANCE_FROM_HEAD_SPHERE, pointOfInterest.z);
|
|
||||||
glColor3f(YELLOW[0], YELLOW[1], YELLOW[2]);
|
|
||||||
renderCircle(haloOrigin, INDICATOR_RADIUS, IDENTITY_UP, NUM_SEGMENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::renderHighlightVoxel(VoxelDetail voxel) {
|
void Application::renderHighlightVoxel(VoxelDetail voxel) {
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
@ -1927,40 +1877,6 @@ void Application::renderHighlightVoxel(VoxelDetail voxel) {
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection) {
|
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
|
|
||||||
|
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
|
||||||
QMutexLocker locker(&node->getMutex());
|
|
||||||
if (node->getLinkedData()) {
|
|
||||||
Avatar *avatar = (Avatar *)node->getLinkedData();
|
|
||||||
if (!avatar->isInitialized()) {
|
|
||||||
avatar->init();
|
|
||||||
}
|
|
||||||
avatar->simulate(deltaTime, NULL);
|
|
||||||
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// simulate avatar fades
|
|
||||||
for (vector<Avatar*>::iterator fade = _avatarFades.begin(); fade != _avatarFades.end(); fade++) {
|
|
||||||
Avatar* avatar = *fade;
|
|
||||||
const float SHRINK_RATE = 0.9f;
|
|
||||||
|
|
||||||
avatar->setTargetScale(avatar->getScale() * SHRINK_RATE);
|
|
||||||
|
|
||||||
const float MIN_FADE_SCALE = 0.001f;
|
|
||||||
|
|
||||||
if (avatar->getTargetScale() < MIN_FADE_SCALE) {
|
|
||||||
delete avatar;
|
|
||||||
_avatarFades.erase(fade--);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
avatar->simulate(deltaTime, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection) {
|
void Application::updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection) {
|
||||||
|
|
||||||
|
@ -2016,7 +1932,7 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3&
|
||||||
_viewFrustum.computePickRay(0.5f, 0.5f, rayOrigin, rayDirection);
|
_viewFrustum.computePickRay(0.5f, 0.5f, rayOrigin, rayDirection);
|
||||||
lookAtSpot = rayOrigin + rayDirection * FAR_AWAY_STARE;
|
lookAtSpot = rayOrigin + rayDirection * FAR_AWAY_STARE;
|
||||||
|
|
||||||
} else if (!_lookatTargetAvatar) {
|
} else if (!_avatarManager.getLookAtTargetAvatar()) {
|
||||||
if (_isHoverVoxel) {
|
if (_isHoverVoxel) {
|
||||||
// Look at the hovered voxel
|
// Look at the hovered voxel
|
||||||
lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel);
|
lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel);
|
||||||
|
@ -2381,7 +2297,7 @@ void Application::update(float deltaTime) {
|
||||||
glm::vec3 lookAtSpot;
|
glm::vec3 lookAtSpot;
|
||||||
|
|
||||||
updateFaceshift();
|
updateFaceshift();
|
||||||
updateLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot);
|
_avatarManager.updateLookAtTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot);
|
||||||
updateMyAvatarLookAtPosition(lookAtSpot, mouseRayOrigin, mouseRayDirection);
|
updateMyAvatarLookAtPosition(lookAtSpot, mouseRayOrigin, mouseRayDirection);
|
||||||
|
|
||||||
// Find the voxel we are hovering over, and respond if clicked
|
// Find the voxel we are hovering over, and respond if clicked
|
||||||
|
@ -2396,7 +2312,7 @@ void Application::update(float deltaTime) {
|
||||||
updateSerialDevices(deltaTime); // Read serial port interface devices
|
updateSerialDevices(deltaTime); // Read serial port interface devices
|
||||||
updateAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
|
updateAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
|
||||||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||||
updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them...
|
_avatarManager.updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them...
|
||||||
updateMyAvatarSimulation(deltaTime); // Simulate myself
|
updateMyAvatarSimulation(deltaTime); // Simulate myself
|
||||||
updateParticles(deltaTime); // Simulate particle cloud movements
|
updateParticles(deltaTime); // Simulate particle cloud movements
|
||||||
updateMetavoxels(deltaTime); // update metavoxels
|
updateMetavoxels(deltaTime); // update metavoxels
|
||||||
|
@ -3145,11 +3061,8 @@ void Application::displayOverlay() {
|
||||||
glPointSize(1.0f);
|
glPointSize(1.0f);
|
||||||
char nodes[100];
|
char nodes[100];
|
||||||
|
|
||||||
int totalAvatars = 0, totalServers = 0;
|
int totalAvatars = _avatarManager.size();
|
||||||
|
int totalServers = NodeList::getInstance()->size();
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
|
||||||
node->getType() == NODE_TYPE_AGENT ? totalAvatars++ : totalServers++;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars);
|
sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars);
|
||||||
drawtext(_glWidget->width() - 150, 20, 0.10f, 0, 1.0f, 0, nodes, 1, 0, 0);
|
drawtext(_glWidget->width() - 150, 20, 0.10f, 0, 1.0f, 0, nodes, 1, 0, 0);
|
||||||
|
@ -3566,43 +3479,7 @@ void Application::renderCoverageMapsRecursively(CoverageMap* map) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) {
|
void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) {
|
||||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
|
||||||
"Application::renderAvatars()");
|
|
||||||
|
|
||||||
if (!selfAvatarOnly) {
|
|
||||||
// Render avatars of other nodes
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
|
||||||
|
|
||||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
|
||||||
QMutexLocker locker(&node->getMutex());
|
|
||||||
|
|
||||||
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
|
|
||||||
Avatar *avatar = (Avatar *)node->getLinkedData();
|
|
||||||
if (!avatar->isInitialized()) {
|
|
||||||
avatar->init();
|
|
||||||
}
|
|
||||||
avatar->render(false);
|
|
||||||
avatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// render avatar fades
|
|
||||||
Glower glower;
|
|
||||||
for (vector<Avatar*>::iterator fade = _avatarFades.begin(); fade != _avatarFades.end(); fade++) {
|
|
||||||
(*fade)->render(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render my own Avatar
|
|
||||||
_myAvatar.render(forceRenderHead);
|
|
||||||
_myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
|
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::LookAtIndicator) && _lookatTargetAvatar) {
|
|
||||||
renderLookatIndicator(_lookatOtherPosition);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderViewFrustum()
|
// renderViewFrustum()
|
||||||
|
@ -3869,17 +3746,6 @@ void Application::setMenuShortcutsEnabled(bool enabled) {
|
||||||
setShortcutsEnabled(_window->menuBar(), enabled);
|
setShortcutsEnabled(_window->menuBar(), enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::attachNewHeadToNode(Node* newNode) {
|
|
||||||
if (newNode->getLinkedData() == NULL) {
|
|
||||||
newNode->setLinkedData(new Avatar(newNode));
|
|
||||||
|
|
||||||
// new UUID requires mesh and skeleton request to data-server
|
|
||||||
DataServerClient::getValuesForKeysAndUUID(QStringList() << DataServerKey::FaceMeshURL << DataServerKey::SkeletonURL,
|
|
||||||
newNode->getUUID(), Application::getInstance()->getProfile());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::updateWindowTitle(){
|
void Application::updateWindowTitle(){
|
||||||
QString title = "";
|
QString title = "";
|
||||||
|
|
||||||
|
@ -3980,16 +3846,9 @@ void Application::nodeKilled(SharedNodePointer node) {
|
||||||
}
|
}
|
||||||
_voxelSceneStatsLock.unlock();
|
_voxelSceneStatsLock.unlock();
|
||||||
|
|
||||||
} else if (node->getType() == NODE_TYPE_AGENT) {
|
} else if (node->getType() == NODE_TYPE_AVATAR_MIXER) {
|
||||||
Avatar* avatar = static_cast<Avatar*>(node->getLinkedData());
|
// our avatar mixer has gone away - clear the hash of avatars
|
||||||
if (avatar == _lookatTargetAvatar) {
|
_avatarManager.clearHash();
|
||||||
_lookatTargetAvatar = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// take over the avatar in order to fade it out
|
|
||||||
node->setLinkedData(NULL);
|
|
||||||
|
|
||||||
_avatarFades.push_back(avatar);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,7 @@ public:
|
||||||
VoxelSystem* getSharedVoxelSystem() { return &_sharedVoxelSystem; }
|
VoxelSystem* getSharedVoxelSystem() { return &_sharedVoxelSystem; }
|
||||||
VoxelTree* getClipboard() { return &_clipboard; }
|
VoxelTree* getClipboard() { return &_clipboard; }
|
||||||
Environment* getEnvironment() { return &_environment; }
|
Environment* getEnvironment() { return &_environment; }
|
||||||
|
bool isMousePressed() const { return _mousePressed; }
|
||||||
bool isMouseHidden() const { return _mouseHidden; }
|
bool isMouseHidden() const { return _mouseHidden; }
|
||||||
Faceshift* getFaceshift() { return &_faceshift; }
|
Faceshift* getFaceshift() { return &_faceshift; }
|
||||||
SixenseManager* getSixenseManager() { return &_sixenseManager; }
|
SixenseManager* getSixenseManager() { return &_sixenseManager; }
|
||||||
|
@ -167,7 +168,6 @@ public:
|
||||||
TextureCache* getTextureCache() { return &_textureCache; }
|
TextureCache* getTextureCache() { return &_textureCache; }
|
||||||
GlowEffect* getGlowEffect() { return &_glowEffect; }
|
GlowEffect* getGlowEffect() { return &_glowEffect; }
|
||||||
|
|
||||||
Avatar* getLookatTargetAvatar() const { return _lookatTargetAvatar; }
|
|
||||||
AvatarManager& getAvatarManager() { return _avatarManager; }
|
AvatarManager& getAvatarManager() { return _avatarManager; }
|
||||||
Profile* getProfile() { return &_profile; }
|
Profile* getProfile() { return &_profile; }
|
||||||
void resetProfile(const QString& username);
|
void resetProfile(const QString& username);
|
||||||
|
@ -275,8 +275,6 @@ private:
|
||||||
float& distance, BoxFace& face);
|
float& distance, BoxFace& face);
|
||||||
void updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
void updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
|
||||||
float& distance, BoxFace& face);
|
float& distance, BoxFace& face);
|
||||||
void updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
|
||||||
glm::vec3& eyePosition);
|
|
||||||
void updateHandAndTouch(float deltaTime);
|
void updateHandAndTouch(float deltaTime);
|
||||||
void updateLeap(float deltaTime);
|
void updateLeap(float deltaTime);
|
||||||
void updateSixense(float deltaTime);
|
void updateSixense(float deltaTime);
|
||||||
|
@ -299,7 +297,6 @@ private:
|
||||||
void renderHighlightVoxel(VoxelDetail voxel);
|
void renderHighlightVoxel(VoxelDetail voxel);
|
||||||
|
|
||||||
void updateAvatar(float deltaTime);
|
void updateAvatar(float deltaTime);
|
||||||
void updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection);
|
|
||||||
void queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, NodeToJurisdictionMap& jurisdictions);
|
void queryOctree(NODE_TYPE serverType, PACKET_TYPE packetType, NodeToJurisdictionMap& jurisdictions);
|
||||||
void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
|
void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
|
||||||
|
|
||||||
|
@ -438,10 +435,6 @@ private:
|
||||||
bool _lookingAwayFromOrigin;
|
bool _lookingAwayFromOrigin;
|
||||||
glm::vec3 _nudgeGuidePosition;
|
glm::vec3 _nudgeGuidePosition;
|
||||||
|
|
||||||
Avatar* _lookatTargetAvatar;
|
|
||||||
glm::vec3 _lookatOtherPosition;
|
|
||||||
float _lookatIndicatorScale;
|
|
||||||
|
|
||||||
glm::vec3 _transmitterPickStart;
|
glm::vec3 _transmitterPickStart;
|
||||||
glm::vec3 _transmitterPickEnd;
|
glm::vec3 _transmitterPickEnd;
|
||||||
|
|
||||||
|
@ -490,7 +483,6 @@ private:
|
||||||
QReadWriteLock _voxelSceneStatsLock;
|
QReadWriteLock _voxelSceneStatsLock;
|
||||||
|
|
||||||
std::vector<VoxelFade> _voxelFades;
|
std::vector<VoxelFade> _voxelFades;
|
||||||
std::vector<Avatar*> _avatarFades;
|
|
||||||
ControllerScriptingInterface _controllerScriptingInterface;
|
ControllerScriptingInterface _controllerScriptingInterface;
|
||||||
QPointer<LogDialog> _logDialog;
|
QPointer<LogDialog> _logDialog;
|
||||||
|
|
||||||
|
|
|
@ -331,7 +331,6 @@ Menu::Menu() :
|
||||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::CollisionProxies);
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::CollisionProxies);
|
||||||
|
|
||||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, true);
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, true);
|
||||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtIndicator, 0, true);
|
|
||||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu,
|
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu,
|
||||||
MenuOption::FaceshiftTCP,
|
MenuOption::FaceshiftTCP,
|
||||||
0,
|
0,
|
||||||
|
@ -899,7 +898,7 @@ void Menu::goToDomain() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
|
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
|
||||||
NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
|
Application::getInstance()->getAvatar()->sendKillAvatar();
|
||||||
|
|
||||||
// give our nodeList the new domain-server hostname
|
// give our nodeList the new domain-server hostname
|
||||||
NodeList::getInstance()->setDomainHostname(domainDialog.textValue());
|
NodeList::getInstance()->setDomainHostname(domainDialog.textValue());
|
||||||
|
@ -941,7 +940,7 @@ void Menu::goToLocation() {
|
||||||
|
|
||||||
if (newAvatarPos != avatarPos) {
|
if (newAvatarPos != avatarPos) {
|
||||||
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
|
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
|
||||||
NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
|
MyAvatar::sendKillAvatar();
|
||||||
|
|
||||||
qDebug("Going To Location: %f, %f, %f...", x, y, z);
|
qDebug("Going To Location: %f, %f, %f...", x, y, z);
|
||||||
myAvatar->setPosition(newAvatarPos);
|
myAvatar->setPosition(newAvatarPos);
|
||||||
|
|
|
@ -217,7 +217,6 @@ namespace MenuOption {
|
||||||
const QString LodTools = "LOD Tools";
|
const QString LodTools = "LOD Tools";
|
||||||
const QString Log = "Log";
|
const QString Log = "Log";
|
||||||
const QString Login = "Login";
|
const QString Login = "Login";
|
||||||
const QString LookAtIndicator = "Look-at Indicator";
|
|
||||||
const QString LookAtVectors = "Look-at Vectors";
|
const QString LookAtVectors = "Look-at Vectors";
|
||||||
const QString Metavoxels = "Metavoxels";
|
const QString Metavoxels = "Metavoxels";
|
||||||
const QString Mirror = "Mirror";
|
const QString Mirror = "Mirror";
|
||||||
|
|
|
@ -87,6 +87,7 @@ Avatar::Avatar(Node* owningNode) :
|
||||||
|
|
||||||
|
|
||||||
Avatar::~Avatar() {
|
Avatar::~Avatar() {
|
||||||
|
qDebug() << "Avatar" << this << "going away";
|
||||||
_headData = NULL;
|
_headData = NULL;
|
||||||
_handData = NULL;
|
_handData = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,50 +6,185 @@
|
||||||
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <PerfStat.h>
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
|
#include "Menu.h"
|
||||||
|
#include "MyAvatar.h"
|
||||||
|
|
||||||
#include "AvatarManager.h"
|
#include "AvatarManager.h"
|
||||||
|
|
||||||
AvatarManager::AvatarManager(QObject* parent) :
|
AvatarManager::AvatarManager(QObject* parent) :
|
||||||
_hash()
|
_lookAtTargetAvatar(),
|
||||||
|
_lookAtOtherPosition(),
|
||||||
|
_lookAtIndicatorScale(1.0f),
|
||||||
|
_avatarHash(),
|
||||||
|
_avatarFades()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarManager::updateLookAtTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
|
glm::vec3 &eyePosition) {
|
||||||
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
|
PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()");
|
||||||
|
|
||||||
|
if (!Application::getInstance()->isMousePressed()) {
|
||||||
|
foreach (const AvatarSharedPointer& avatar, _avatarHash) {
|
||||||
|
float distance;
|
||||||
|
|
||||||
|
if (avatar->findRayIntersection(mouseRayOrigin, mouseRayDirection, distance)) {
|
||||||
|
// rescale to compensate for head embiggening
|
||||||
|
eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) *
|
||||||
|
(avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot();
|
||||||
|
|
||||||
|
_lookAtIndicatorScale = avatar->getHead().getScale();
|
||||||
|
_lookAtOtherPosition = avatar->getHead().getPosition();
|
||||||
|
|
||||||
|
_lookAtTargetAvatar = avatar;
|
||||||
|
|
||||||
|
// found the look at target avatar, return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_lookAtTargetAvatar.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarManager::updateAvatars(float deltaTime, const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection) {
|
||||||
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
|
PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
|
||||||
|
|
||||||
|
// simulate avatars
|
||||||
|
foreach (const AvatarSharedPointer& avatar, _avatarHash) {
|
||||||
|
avatar->simulate(deltaTime, NULL);
|
||||||
|
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulate avatar fades
|
||||||
|
simulateAvatarFades(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarManager::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) {
|
||||||
|
if (!Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::renderAvatars()");
|
||||||
|
|
||||||
|
if (!selfAvatarOnly) {
|
||||||
|
|
||||||
|
// Render avatars of other nodes
|
||||||
|
foreach (const AvatarSharedPointer& avatar, _avatarHash) {
|
||||||
|
if (!avatar->isInitialized()) {
|
||||||
|
avatar->init();
|
||||||
|
}
|
||||||
|
avatar->render(false);
|
||||||
|
avatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAvatarFades();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render my own Avatar
|
||||||
|
Avatar* myAvatar = Application::getInstance()->getAvatar();
|
||||||
|
myAvatar->render(forceRenderHead);
|
||||||
|
myAvatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarManager::simulateAvatarFades(float deltaTime) {
|
||||||
|
QVector<AvatarSharedPointer>::iterator fadingAvatar = _avatarFades.begin();
|
||||||
|
|
||||||
|
while (fadingAvatar != _avatarFades.end()) {
|
||||||
|
const float SHRINK_RATE = 0.9f;
|
||||||
|
|
||||||
|
fadingAvatar->data()->setTargetScale(fadingAvatar->data()->getScale() * SHRINK_RATE);
|
||||||
|
|
||||||
|
const float MIN_FADE_SCALE = 0.001f;
|
||||||
|
|
||||||
|
if (fadingAvatar->data()->getTargetScale() < MIN_FADE_SCALE) {
|
||||||
|
qDebug() << "Fade for" << fadingAvatar->data() << "over";
|
||||||
|
fadingAvatar = _avatarFades.erase(fadingAvatar);
|
||||||
|
} else {
|
||||||
|
fadingAvatar->data()->simulate(deltaTime, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarManager::renderAvatarFades() {
|
||||||
|
// render avatar fades
|
||||||
|
Glower glower;
|
||||||
|
|
||||||
|
foreach(const AvatarSharedPointer& fadingAvatar, _avatarFades) {
|
||||||
|
fadingAvatar->render(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AvatarManager::processDataServerResponse(const QString& userString, const QStringList& keyList,
|
||||||
|
const QStringList &valueList) {
|
||||||
|
for (int i = 0; i < keyList.size(); i++) {
|
||||||
|
if (valueList[i] != " ") {
|
||||||
|
if (keyList[i] == DataServerKey::FaceMeshURL || keyList[i] == DataServerKey::SkeletonURL) {
|
||||||
|
// mesh URL for a UUID, find avatar in our list
|
||||||
|
AvatarSharedPointer matchingAvatar = _avatarHash.value(QUuid(userString));
|
||||||
|
if (matchingAvatar) {
|
||||||
|
if (keyList[i] == DataServerKey::FaceMeshURL) {
|
||||||
|
qDebug() << "Changing mesh to" << valueList[i] << "for avatar with UUID"
|
||||||
|
<< uuidStringWithoutCurlyBraces(QUuid(userString));
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(&matchingAvatar->getHead().getFaceModel(),
|
||||||
|
"setURL", Q_ARG(QUrl, QUrl(valueList[i])));
|
||||||
|
} else if (keyList[i] == DataServerKey::SkeletonURL) {
|
||||||
|
qDebug() << "Changing skeleton to" << valueList[i] << "for avatar with UUID"
|
||||||
|
<< uuidStringWithoutCurlyBraces(QString(userString));
|
||||||
|
|
||||||
|
QMetaObject::invokeMethod(&matchingAvatar->getSkeletonModel(),
|
||||||
|
"setURL", Q_ARG(QUrl, QUrl(valueList[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram) {
|
void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram) {
|
||||||
unsigned char packetData[MAX_PACKET_SIZE];
|
unsigned char packetData[MAX_PACKET_SIZE];
|
||||||
memcpy(packetData, datagram.data(), datagram.size());
|
memcpy(packetData, datagram.data(), datagram.size());
|
||||||
|
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
|
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
|
||||||
|
|
||||||
QUuid nodeUUID = QUuid::fromRfc4122(datagram.mid(numBytesPacketHeader, NUM_BYTES_RFC4122_UUID));
|
|
||||||
|
|
||||||
int bytesRead = numBytesPacketHeader;
|
int bytesRead = numBytesPacketHeader;
|
||||||
|
|
||||||
unsigned char avatarData[MAX_PACKET_SIZE];
|
unsigned char avatarData[MAX_PACKET_SIZE];
|
||||||
populateTypeAndVersion(avatarData, PACKET_TYPE_HEAD_DATA);
|
int numBytesDummyPacketHeader = populateTypeAndVersion(avatarData, PACKET_TYPE_HEAD_DATA);
|
||||||
|
|
||||||
while (bytesRead < datagram.size()) {
|
while (bytesRead < datagram.size()) {
|
||||||
Avatar* matchingAvatar = _hash.value(nodeUUID);
|
QUuid nodeUUID = QUuid::fromRfc4122(datagram.mid(bytesRead, NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
|
AvatarSharedPointer matchingAvatar = _avatarHash.value(nodeUUID);
|
||||||
|
|
||||||
if (!matchingAvatar) {
|
if (!matchingAvatar) {
|
||||||
// construct a new Avatar for this node
|
// construct a new Avatar for this node
|
||||||
matchingAvatar = new Avatar();
|
matchingAvatar = AvatarSharedPointer(new Avatar());
|
||||||
|
|
||||||
// insert the new avatar into our hash
|
// insert the new avatar into our hash
|
||||||
_hash.insert(nodeUUID, matchingAvatar);
|
_avatarHash.insert(nodeUUID, matchingAvatar);
|
||||||
|
|
||||||
|
// new UUID requires mesh and skeleton request to data-server
|
||||||
|
DataServerClient::getValuesForKeysAndUUID(QStringList() << DataServerKey::FaceMeshURL << DataServerKey::SkeletonURL,
|
||||||
|
nodeUUID, this);
|
||||||
|
|
||||||
qDebug() << "Adding avatar with UUID" << nodeUUID << "to AvatarManager hash.";
|
qDebug() << "Adding avatar with UUID" << nodeUUID << "to AvatarManager hash.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy the rest of the packet to the avatarData holder so we can read the next Avatar from there
|
// copy the rest of the packet to the avatarData holder so we can read the next Avatar from there
|
||||||
memcpy(avatarData, packetData + bytesRead, datagram.size() - bytesRead);
|
memcpy(avatarData + numBytesDummyPacketHeader, packetData + bytesRead, datagram.size() - bytesRead);
|
||||||
|
|
||||||
// have the matching (or new) avatar parse the data from the packet
|
// have the matching (or new) avatar parse the data from the packet
|
||||||
bytesRead += matchingAvatar->parseData(avatarData,
|
bytesRead += matchingAvatar->parseData(avatarData, datagram.size() - bytesRead);
|
||||||
datagram.size() - bytesRead);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,11 +194,16 @@ void AvatarManager::processKillAvatar(const QByteArray& datagram) {
|
||||||
(datagram.data())),
|
(datagram.data())),
|
||||||
NUM_BYTES_RFC4122_UUID));
|
NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
// kill the avatar with that UUID from our hash, if it exists
|
// remove the avatar with that UUID from our hash, if it exists
|
||||||
_hash.remove(nodeUUID);
|
AvatarSharedPointer removedAvatar = _avatarHash.take(nodeUUID);
|
||||||
|
|
||||||
|
if (removedAvatar) {
|
||||||
|
// add this avatar to our vector of fades
|
||||||
|
_avatarFades.push_back(removedAvatar);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarManager::clearHash() {
|
void AvatarManager::clearHash() {
|
||||||
// clear the AvatarManager hash - typically happens on the removal of the avatar-mixer
|
// clear the AvatarManager hash - typically happens on the removal of the avatar-mixer
|
||||||
_hash.clear();
|
_avatarHash.clear();
|
||||||
}
|
}
|
|
@ -11,19 +11,49 @@
|
||||||
|
|
||||||
#include <QtCore/QHash>
|
#include <QtCore/QHash>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/QSharedPointer>
|
||||||
|
|
||||||
|
#include <DataServerClient.h>
|
||||||
|
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
|
|
||||||
class AvatarManager : public QObject {
|
typedef QSharedPointer<Avatar> AvatarSharedPointer;
|
||||||
|
typedef QHash<QUuid, AvatarSharedPointer> AvatarHash;
|
||||||
|
|
||||||
|
class AvatarManager : public QObject, public DataServerCallbackObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
AvatarManager(QObject* parent = 0);
|
AvatarManager(QObject* parent = 0);
|
||||||
|
|
||||||
|
const AvatarHash& getAvatarHash() { return _avatarHash; }
|
||||||
|
int size() const { return _avatarHash.size(); }
|
||||||
|
|
||||||
|
Avatar* getLookAtTargetAvatar() const { return _lookAtTargetAvatar.data(); }
|
||||||
|
|
||||||
|
void updateLookAtTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
|
glm::vec3& eyePosition);
|
||||||
|
|
||||||
|
void updateAvatars(float deltaTime, const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection);
|
||||||
|
void renderAvatars(bool forceRenderHead, bool selfAvatarOnly);
|
||||||
|
|
||||||
|
void clearHash();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void processDataServerResponse(const QString& userString, const QStringList& keyList, const QStringList& valueList);
|
||||||
|
|
||||||
void processAvatarMixerDatagram(const QByteArray& datagram);
|
void processAvatarMixerDatagram(const QByteArray& datagram);
|
||||||
void processKillAvatar(const QByteArray& datagram);
|
void processKillAvatar(const QByteArray& datagram);
|
||||||
void clearHash();
|
|
||||||
private:
|
private:
|
||||||
QHash<QUuid, Avatar*> _hash;
|
void simulateAvatarFades(float deltaTime);
|
||||||
|
void renderAvatarFades();
|
||||||
|
|
||||||
|
QWeakPointer<Avatar> _lookAtTargetAvatar;
|
||||||
|
glm::vec3 _lookAtOtherPosition;
|
||||||
|
float _lookAtIndicatorScale;
|
||||||
|
|
||||||
|
AvatarHash _avatarHash;
|
||||||
|
QVector<AvatarSharedPointer> _avatarFades;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__AvatarManager__) */
|
#endif /* defined(__hifi__AvatarManager__) */
|
||||||
|
|
|
@ -185,49 +185,46 @@ void Hand::updateCollisions() {
|
||||||
glm::vec3 totalPenetration;
|
glm::vec3 totalPenetration;
|
||||||
|
|
||||||
// check other avatars
|
// check other avatars
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
foreach (const AvatarSharedPointer& avatar, Application::getInstance()->getAvatarManager().getAvatarHash()) {
|
||||||
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) {
|
||||||
Avatar* otherAvatar = (Avatar*)node->getLinkedData();
|
// Check for palm collisions
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) {
|
glm::vec3 myPalmPosition = palm.getPosition();
|
||||||
// Check for palm collisions
|
float palmCollisionDistance = 0.1f;
|
||||||
glm::vec3 myPalmPosition = palm.getPosition();
|
bool wasColliding = palm.getIsCollidingWithPalm();
|
||||||
float palmCollisionDistance = 0.1f;
|
palm.setIsCollidingWithPalm(false);
|
||||||
bool wasColliding = palm.getIsCollidingWithPalm();
|
// If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound
|
||||||
palm.setIsCollidingWithPalm(false);
|
for (size_t j = 0; j < avatar->getHand().getNumPalms(); j++) {
|
||||||
// If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound
|
PalmData& otherPalm = avatar->getHand().getPalms()[j];
|
||||||
for (size_t j = 0; j < otherAvatar->getHand().getNumPalms(); j++) {
|
if (!otherPalm.isActive()) {
|
||||||
PalmData& otherPalm = otherAvatar->getHand().getPalms()[j];
|
continue;
|
||||||
if (!otherPalm.isActive()) {
|
}
|
||||||
continue;
|
glm::vec3 otherPalmPosition = otherPalm.getPosition();
|
||||||
}
|
if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) {
|
||||||
glm::vec3 otherPalmPosition = otherPalm.getPosition();
|
palm.setIsCollidingWithPalm(true);
|
||||||
if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) {
|
if (!wasColliding) {
|
||||||
palm.setIsCollidingWithPalm(true);
|
const float PALM_COLLIDE_VOLUME = 1.f;
|
||||||
if (!wasColliding) {
|
const float PALM_COLLIDE_FREQUENCY = 1000.f;
|
||||||
const float PALM_COLLIDE_VOLUME = 1.f;
|
const float PALM_COLLIDE_DURATION_MAX = 0.75f;
|
||||||
const float PALM_COLLIDE_FREQUENCY = 1000.f;
|
const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f;
|
||||||
const float PALM_COLLIDE_DURATION_MAX = 0.75f;
|
Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME,
|
||||||
const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f;
|
PALM_COLLIDE_FREQUENCY,
|
||||||
Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME,
|
PALM_COLLIDE_DURATION_MAX,
|
||||||
PALM_COLLIDE_FREQUENCY,
|
PALM_COLLIDE_DECAY_PER_SAMPLE);
|
||||||
PALM_COLLIDE_DURATION_MAX,
|
// If the other person's palm is in motion, move mine downward to show I was hit
|
||||||
PALM_COLLIDE_DECAY_PER_SAMPLE);
|
const float MIN_VELOCITY_FOR_SLAP = 0.05f;
|
||||||
// If the other person's palm is in motion, move mine downward to show I was hit
|
if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) {
|
||||||
const float MIN_VELOCITY_FOR_SLAP = 0.05f;
|
// add slapback here
|
||||||
if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) {
|
|
||||||
// add slapback here
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glm::vec3 avatarPenetration;
|
}
|
||||||
if (otherAvatar->findSpherePenetration(palm.getPosition(), scaledPalmRadius, avatarPenetration)) {
|
glm::vec3 avatarPenetration;
|
||||||
totalPenetration = addPenetrations(totalPenetration, avatarPenetration);
|
if (avatar->findSpherePenetration(palm.getPosition(), scaledPalmRadius, avatarPenetration)) {
|
||||||
// Check for collisions with the other avatar's leap palms
|
totalPenetration = addPenetrations(totalPenetration, avatarPenetration);
|
||||||
}
|
// Check for collisions with the other avatar's leap palms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -791,16 +791,16 @@ void MyAvatar::updateChatCircle(float deltaTime) {
|
||||||
// find all circle-enabled members and sort by distance
|
// find all circle-enabled members and sort by distance
|
||||||
QVector<SortedAvatar> sortedAvatars;
|
QVector<SortedAvatar> sortedAvatars;
|
||||||
|
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
foreach (const AvatarSharedPointer& avatar, Application::getInstance()->getAvatarManager().getAvatarHash()) {
|
||||||
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
|
SortedAvatar sortedAvatar;
|
||||||
SortedAvatar sortedAvatar;
|
sortedAvatar.avatar = avatar.data();
|
||||||
sortedAvatar.avatar = (Avatar*)node->getLinkedData();
|
|
||||||
if (!sortedAvatar.avatar->isChatCirclingEnabled()) {
|
if (!sortedAvatar.avatar->isChatCirclingEnabled()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
sortedAvatar.distance = glm::distance(_position, sortedAvatar.avatar->getPosition());
|
|
||||||
sortedAvatars.append(sortedAvatar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sortedAvatar.distance = glm::distance(_position, sortedAvatar.avatar->getPosition());
|
||||||
|
sortedAvatars.append(sortedAvatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
qSort(sortedAvatars.begin(), sortedAvatars.end());
|
qSort(sortedAvatars.begin(), sortedAvatars.end());
|
||||||
|
|
|
@ -63,7 +63,7 @@ public:
|
||||||
bool getDriveKeys(int key) { return _driveKeys[key]; };
|
bool getDriveKeys(int key) { return _driveKeys[key]; };
|
||||||
void jump() { _shouldJump = true; };
|
void jump() { _shouldJump = true; };
|
||||||
|
|
||||||
void sendKillAvatar();
|
static void sendKillAvatar();
|
||||||
|
|
||||||
// Set/Get update the thrust that will move the avatar around
|
// Set/Get update the thrust that will move the avatar around
|
||||||
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
||||||
|
|
|
@ -158,35 +158,11 @@ void Profile::processDataServerResponse(const QString& userString, const QString
|
||||||
if (userString == _username || userString == uuidStringWithoutCurlyBraces(_uuid)) {
|
if (userString == _username || userString == uuidStringWithoutCurlyBraces(_uuid)) {
|
||||||
qDebug("Changing user's face model URL to %s", valueList[i].toLocal8Bit().constData());
|
qDebug("Changing user's face model URL to %s", valueList[i].toLocal8Bit().constData());
|
||||||
Application::getInstance()->getProfile()->setFaceModelURL(QUrl(valueList[i]));
|
Application::getInstance()->getProfile()->setFaceModelURL(QUrl(valueList[i]));
|
||||||
} else {
|
|
||||||
// mesh URL for a UUID, find avatar in our list
|
|
||||||
SharedNodePointer matchingNode = NodeList::getInstance()->nodeWithUUID(QUuid(userString));
|
|
||||||
if (matchingNode && matchingNode->getType() == NODE_TYPE_AGENT) {
|
|
||||||
qDebug() << "Changing mesh to" << valueList[i] << "for avatar with UUID"
|
|
||||||
<< uuidStringWithoutCurlyBraces(matchingNode->getUUID());
|
|
||||||
|
|
||||||
Avatar* avatar = (Avatar *) matchingNode->getLinkedData();
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(&avatar->getHead().getFaceModel(),
|
|
||||||
"setURL", Q_ARG(QUrl, QUrl(valueList[i])));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (keyList[i] == DataServerKey::SkeletonURL) {
|
} else if (keyList[i] == DataServerKey::SkeletonURL) {
|
||||||
if (userString == _username || userString == uuidStringWithoutCurlyBraces(_uuid)) {
|
if (userString == _username || userString == uuidStringWithoutCurlyBraces(_uuid)) {
|
||||||
qDebug("Changing user's skeleton URL to %s", valueList[i].toLocal8Bit().constData());
|
qDebug("Changing user's skeleton URL to %s", valueList[i].toLocal8Bit().constData());
|
||||||
Application::getInstance()->getProfile()->setSkeletonModelURL(QUrl(valueList[i]));
|
Application::getInstance()->getProfile()->setSkeletonModelURL(QUrl(valueList[i]));
|
||||||
} else {
|
|
||||||
// skeleton URL for a UUID, find avatar in our list
|
|
||||||
SharedNodePointer matchingNode = NodeList::getInstance()->nodeWithUUID(QUuid(userString));
|
|
||||||
if (matchingNode && matchingNode->getType() == NODE_TYPE_AGENT) {
|
|
||||||
qDebug() << "Changing skeleton to" << valueList[i] << "for avatar with UUID"
|
|
||||||
<< uuidStringWithoutCurlyBraces(matchingNode->getUUID());
|
|
||||||
|
|
||||||
Avatar* avatar = (Avatar *) matchingNode->getLinkedData();
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(&avatar->getSkeletonModel(),
|
|
||||||
"setURL", Q_ARG(QUrl, QUrl(valueList[i])));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (keyList[i] == DataServerKey::Domain && keyList[i + 1] == DataServerKey::Position &&
|
} else if (keyList[i] == DataServerKey::Domain && keyList[i + 1] == DataServerKey::Position &&
|
||||||
keyList[i + 2] == DataServerKey::Orientation && valueList[i] != " " &&
|
keyList[i + 2] == DataServerKey::Orientation && valueList[i] != " " &&
|
||||||
|
@ -198,7 +174,7 @@ void Profile::processDataServerResponse(const QString& userString, const QString
|
||||||
if (coordinateItems.size() == 3 && orientationItems.size() == 3) {
|
if (coordinateItems.size() == 3 && orientationItems.size() == 3) {
|
||||||
|
|
||||||
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
|
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
|
||||||
NodeList::getInstance()->sendKillNode(&NODE_TYPE_AVATAR_MIXER, 1);
|
MyAvatar::sendKillAvatar();
|
||||||
|
|
||||||
qDebug() << "Changing domain to" << valueList[i].toLocal8Bit().constData() <<
|
qDebug() << "Changing domain to" << valueList[i].toLocal8Bit().constData() <<
|
||||||
", position to" << valueList[i + 1].toLocal8Bit().constData() <<
|
", position to" << valueList[i + 1].toLocal8Bit().constData() <<
|
||||||
|
@ -211,8 +187,7 @@ void Profile::processDataServerResponse(const QString& userString, const QString
|
||||||
orientationItems[1].toFloat(),
|
orientationItems[1].toFloat(),
|
||||||
orientationItems[2].toFloat()))) *
|
orientationItems[2].toFloat()))) *
|
||||||
glm::angleAxis(180.0f, 0.0f, 1.0f, 0.0f);
|
glm::angleAxis(180.0f, 0.0f, 1.0f, 0.0f);
|
||||||
Application::getInstance()->getAvatar()
|
Application::getInstance()->getAvatar()->setOrientation(newOrientation);
|
||||||
->setOrientation(newOrientation);
|
|
||||||
|
|
||||||
// move the user a couple units away
|
// move the user a couple units away
|
||||||
const float DISTANCE_TO_USER = 2.0f;
|
const float DISTANCE_TO_USER = 2.0f;
|
||||||
|
|
|
@ -192,37 +192,37 @@ void ParticleCollisionSystem::updateCollisionWithAvatars(Particle* particle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop through all the other avatars for potential interactions...
|
// loop through all the other avatars for potential interactions...
|
||||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
// foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||||
//qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n";
|
// //qDebug() << "updateCollisionWithAvatars()... node:" << *node << "\n";
|
||||||
if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
|
// if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) {
|
||||||
AvatarData* avatar = static_cast<AvatarData*>(node->getLinkedData());
|
// AvatarData* avatar = static_cast<AvatarData*>(node->getLinkedData());
|
||||||
CollisionInfo collisionInfo;
|
// CollisionInfo collisionInfo;
|
||||||
if (avatar->findSphereCollision(center, radius, collisionInfo)) {
|
// if (avatar->findSphereCollision(center, radius, collisionInfo)) {
|
||||||
collisionInfo._addedVelocity /= (float)(TREE_SCALE);
|
// collisionInfo._addedVelocity /= (float)(TREE_SCALE);
|
||||||
glm::vec3 relativeVelocity = collisionInfo._addedVelocity - particle->getVelocity();
|
// glm::vec3 relativeVelocity = collisionInfo._addedVelocity - particle->getVelocity();
|
||||||
if (glm::dot(relativeVelocity, collisionInfo._penetration) < 0.f) {
|
// if (glm::dot(relativeVelocity, collisionInfo._penetration) < 0.f) {
|
||||||
// HACK BEGIN: to allow paddle hands to "hold" particles we attenuate soft collisions against the avatar.
|
// // HACK BEGIN: to allow paddle hands to "hold" particles we attenuate soft collisions against the avatar.
|
||||||
// NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
|
// // NOTE: the physics are wrong (particles cannot roll) but it IS possible to catch a slow moving particle.
|
||||||
// TODO: make this less hacky when we have more per-collision details
|
// // TODO: make this less hacky when we have more per-collision details
|
||||||
float elasticity = ELASTICITY;
|
// float elasticity = ELASTICITY;
|
||||||
float attenuationFactor = glm::length(collisionInfo._addedVelocity) / HALTING_SPEED;
|
// float attenuationFactor = glm::length(collisionInfo._addedVelocity) / HALTING_SPEED;
|
||||||
float damping = DAMPING;
|
// float damping = DAMPING;
|
||||||
if (attenuationFactor < 1.f) {
|
// if (attenuationFactor < 1.f) {
|
||||||
collisionInfo._addedVelocity *= attenuationFactor;
|
// collisionInfo._addedVelocity *= attenuationFactor;
|
||||||
elasticity *= attenuationFactor;
|
// elasticity *= attenuationFactor;
|
||||||
// NOTE: the math below keeps the damping piecewise continuous,
|
// // NOTE: the math below keeps the damping piecewise continuous,
|
||||||
// while ramping it up to 1.0 when attenuationFactor = 0
|
// // while ramping it up to 1.0 when attenuationFactor = 0
|
||||||
damping = DAMPING + (1.f - attenuationFactor) * (1.f - DAMPING);
|
// damping = DAMPING + (1.f - attenuationFactor) * (1.f - DAMPING);
|
||||||
}
|
// }
|
||||||
// HACK END
|
// // HACK END
|
||||||
|
//
|
||||||
collisionInfo._penetration /= (float)(TREE_SCALE);
|
// collisionInfo._penetration /= (float)(TREE_SCALE);
|
||||||
updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY);
|
// updateCollisionSound(particle, collisionInfo._penetration, COLLISION_FREQUENCY);
|
||||||
applyHardCollision(particle, ELASTICITY, damping, collisionInfo);
|
// applyHardCollision(particle, ELASTICITY, damping, collisionInfo);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: convert applyHardCollision() to take a CollisionInfo& instead of penetration + addedVelocity
|
// TODO: convert applyHardCollision() to take a CollisionInfo& instead of penetration + addedVelocity
|
||||||
|
|
|
@ -102,8 +102,6 @@ public:
|
||||||
int fillPingPacket(unsigned char* buffer);
|
int fillPingPacket(unsigned char* buffer);
|
||||||
int fillPingReplyPacket(unsigned char* pingBuffer, unsigned char* replyBuffer);
|
int fillPingReplyPacket(unsigned char* pingBuffer, unsigned char* replyBuffer);
|
||||||
void pingPublicAndLocalSocketsForInactiveNode(Node* node);
|
void pingPublicAndLocalSocketsForInactiveNode(Node* node);
|
||||||
|
|
||||||
void sendKillNode(const char* nodeTypes, int numNodeTypes);
|
|
||||||
|
|
||||||
SharedNodePointer nodeWithAddress(const HifiSockAddr& senderSockAddr);
|
SharedNodePointer nodeWithAddress(const HifiSockAddr& senderSockAddr);
|
||||||
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
||||||
|
|
Loading…
Reference in a new issue