From 95971b830326026ee02aa878922a9cf3649473fe Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 14:12:42 -0700 Subject: [PATCH 01/71] rename AGENT_TYPE_VOXEL and PACKET_HEADER_DOMAIN_RFD --- animation-server/src/main.cpp | 14 +++++++------- domain-server/src/main.cpp | 6 +++--- libraries/shared/src/Agent.cpp | 6 +++--- libraries/shared/src/AgentList.cpp | 20 ++++++++------------ libraries/shared/src/AgentList.h | 11 +++++++---- libraries/shared/src/AgentTypes.h | 6 ++---- libraries/shared/src/PacketHeaders.h | 2 +- 7 files changed, 31 insertions(+), 34 deletions(-) diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index c29521ec7d..9878d2e6a4 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -59,7 +59,7 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { printf("sending packet of size=%d\n",sizeOut); } - AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1); delete[] bufferOut; } } @@ -168,7 +168,7 @@ static void renderMovingBug() { if (::shouldShowPacketsPerSecond) { printf("sending packet of size=%d\n", sizeOut); } - AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1); delete[] bufferOut; } @@ -238,7 +238,7 @@ static void renderMovingBug() { if (::shouldShowPacketsPerSecond) { printf("sending packet of size=%d\n", sizeOut); } - AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1); delete[] bufferOut; } } @@ -345,7 +345,7 @@ static void sendBlinkingStringOfLights() { if (::shouldShowPacketsPerSecond) { printf("sending packet of size=%d\n",sizeOut); } - AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1); delete[] bufferOut; } @@ -387,7 +387,7 @@ static void sendBlinkingStringOfLights() { if (::shouldShowPacketsPerSecond) { printf("sending packet of size=%d\n",sizeOut); } - AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1); delete[] bufferOut; } } @@ -510,7 +510,7 @@ void sendDanceFloor() { if (::shouldShowPacketsPerSecond) { printf("sending packet of size=%d\n", sizeOut); } - AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1); delete[] bufferOut; } } @@ -607,7 +607,7 @@ static void sendBillboard() { if (::shouldShowPacketsPerSecond) { printf("sending packet of size=%d\n", sizeOut); } - AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1); delete[] bufferOut; } } diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 968057623f..b38ae5b824 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -98,7 +98,7 @@ int main(int argc, const char * argv[]) while (true) { if (agentList->getAgentSocket()->receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes) && - (packetData[0] == PACKET_HEADER_DOMAIN_RFD || packetData[0] == PACKET_HEADER_DOMAIN_LIST_REQUEST)) { + (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_HEADER_DOMAIN_LIST_REQUEST)) { std::map newestSoloAgents; agentType = packetData[1]; @@ -153,10 +153,10 @@ int main(int argc, const char * argv[]) // grab the ID for this agent so we can send it back with the packet packetAgentID = agent->getAgentID(); - if (packetData[0] == PACKET_HEADER_DOMAIN_RFD + if (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY && memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) { agent->setWakeMicrostamp(timeNow); - } + } } } diff --git a/libraries/shared/src/Agent.cpp b/libraries/shared/src/Agent.cpp index 09fe6a1459..4556f670d6 100644 --- a/libraries/shared/src/Agent.cpp +++ b/libraries/shared/src/Agent.cpp @@ -62,7 +62,7 @@ Agent::~Agent() { // Names of Agent Types const char* AGENT_TYPE_NAME_DOMAIN = "Domain"; -const char* AGENT_TYPE_NAME_VOXEL = "Voxel Server"; +const char* AGENT_TYPE_NAME_VOXEL_SERVER = "Voxel Server"; const char* AGENT_TYPE_NAME_INTERFACE = "Client Interface"; const char* AGENT_TYPE_NAME_AUDIO_MIXER = "Audio Mixer"; const char* AGENT_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer"; @@ -74,8 +74,8 @@ const char* Agent::getTypeName() const { switch (this->_type) { case AGENT_TYPE_DOMAIN: return AGENT_TYPE_NAME_DOMAIN; - case AGENT_TYPE_VOXEL: - return AGENT_TYPE_NAME_VOXEL; + case AGENT_TYPE_VOXEL_SERVER: + return AGENT_TYPE_NAME_VOXEL_SERVER; case AGENT_TYPE_AVATAR: return AGENT_TYPE_NAME_INTERFACE; case AGENT_TYPE_AUDIO_MIXER: diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 51ef88794b..53aad60cd3 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -26,7 +26,7 @@ const char SOLO_AGENT_TYPES[3] = { AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_AUDIO_MIXER, - AGENT_TYPE_VOXEL + AGENT_TYPE_VOXEL_SERVER }; char DOMAIN_HOSTNAME[] = "highfidelity.below92.com"; @@ -60,9 +60,9 @@ AgentList* AgentList::getInstance() { AgentList::AgentList(char newOwnerType, unsigned int newSocketListenPort) : _agentBuckets(), _numAgents(0), - agentSocket(newSocketListenPort), + _agentSocket(newSocketListenPort), _ownerType(newOwnerType), - socketListenPort(newSocketListenPort), + _socketListenPort(newSocketListenPort), _ownerID(UNKNOWN_AGENT_ID), _lastAgentID(0) { pthread_mutex_init(&mutex, 0); @@ -77,10 +77,6 @@ AgentList::~AgentList() { pthread_mutex_destroy(&mutex); } -unsigned int AgentList::getSocketListenPort() { - return socketListenPort; -} - void AgentList::processAgentData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) { switch (((char *)packetData)[0]) { case PACKET_HEADER_DOMAIN: { @@ -88,7 +84,7 @@ void AgentList::processAgentData(sockaddr *senderAddress, unsigned char *packetD break; } case PACKET_HEADER_PING: { - agentSocket.send(senderAddress, &PACKET_HEADER_PING_REPLY, 1); + _agentSocket.send(senderAddress, &PACKET_HEADER_PING_REPLY, 1); break; } case PACKET_HEADER_PING_REPLY: { @@ -233,7 +229,7 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket newAgent->activatePublicSocket(); } - if (newAgent->getType() == AGENT_TYPE_VOXEL || + if (newAgent->getType() == AGENT_TYPE_VOXEL_SERVER || newAgent->getType() == AGENT_TYPE_AVATAR_MIXER || newAgent->getType() == AGENT_TYPE_AUDIO_MIXER) { // this is currently the cheat we use to talk directly to our test servers on EC2 @@ -247,7 +243,7 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket } else { if (agent->getType() == AGENT_TYPE_AUDIO_MIXER || - agent->getType() == AGENT_TYPE_VOXEL || + agent->getType() == AGENT_TYPE_VOXEL_SERVER || agent->getType() == AGENT_TYPE_ANIMATION_SERVER || agent->getType() == AGENT_TYPE_AUDIO_INJECTOR) { // until the Audio class also uses our agentList, we need to update @@ -281,7 +277,7 @@ void AgentList::broadcastToAgents(unsigned char *broadcastData, size_t dataBytes // only send to the AgentTypes we are asked to send to. if (agent->getActiveSocket() != NULL && memchr(agentTypes, agent->getType(), numAgentTypes)) { // we know which socket is good for this agent, send there - agentSocket.send(agent->getActiveSocket(), broadcastData, dataBytes); + _agentSocket.send(agent->getActiveSocket(), broadcastData, dataBytes); } } } @@ -362,7 +358,7 @@ void *removeSilentAgents(void *args) { for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); ++agent) { if ((checkTimeUSecs - agent->getLastHeardMicrostamp()) > AGENT_SILENCE_THRESHOLD_USECS - && agent->getType() != AGENT_TYPE_VOXEL) { + && agent->getType() != AGENT_TYPE_VOXEL_SERVER) { printLog("Killed "); Agent::printLog(*agent); diff --git a/libraries/shared/src/AgentList.h b/libraries/shared/src/AgentList.h index 3ac7cf1f8d..e5db88569c 100644 --- a/libraries/shared/src/AgentList.h +++ b/libraries/shared/src/AgentList.h @@ -24,6 +24,7 @@ const int AGENTS_PER_BUCKET = 100; const int MAX_PACKET_SIZE = 1500; const unsigned int AGENT_SOCKET_LISTEN_PORT = 40103; + const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000; extern const char SOLO_AGENT_TYPES[3]; @@ -49,8 +50,6 @@ public: int size() { return _numAgents; } - UDPSocket* getAgentSocket() { return &agentSocket; } - void lock() { pthread_mutex_lock(&mutex); } void unlock() { pthread_mutex_unlock(&mutex); } @@ -78,6 +77,10 @@ public: uint16_t getOwnerID() const { return _ownerID; } void setOwnerID(uint16_t ownerID) { _ownerID = ownerID; } + UDPSocket* getAgentSocket() { return &_agentSocket; } + + unsigned int getSocketListenPort() const { return _socketListenPort; }; + Agent* soloAgentOfType(char agentType); void startSilentAgentRemovalThread(); @@ -100,9 +103,9 @@ private: Agent** _agentBuckets[MAX_NUM_AGENTS / AGENTS_PER_BUCKET]; int _numAgents; - UDPSocket agentSocket; + UDPSocket _agentSocket; char _ownerType; - unsigned int socketListenPort; + unsigned int _socketListenPort; uint16_t _ownerID; uint16_t _lastAgentID; pthread_t removeSilentAgentsThread; diff --git a/libraries/shared/src/AgentTypes.h b/libraries/shared/src/AgentTypes.h index 4f3100fe03..8bc97b5ba3 100644 --- a/libraries/shared/src/AgentTypes.h +++ b/libraries/shared/src/AgentTypes.h @@ -3,11 +3,10 @@ // hifi // // Created by Brad Hefta-Gaub on 2013/04/09 -// +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // // Single byte/character Agent Types used to identify various agents in the system. // For example, an agent whose is 'V' is always a voxel server. -// #ifndef hifi_AgentTypes_h #define hifi_AgentTypes_h @@ -17,9 +16,8 @@ // If you don't then it will make things harder on your co-developers in debugging because the Agent // class won't know the name and will report it as "Unknown". -// Agent Type Codes const char AGENT_TYPE_DOMAIN = 'D'; -const char AGENT_TYPE_VOXEL = 'V'; +const char AGENT_TYPE_VOXEL_SERVER = 'V'; const char AGENT_TYPE_AVATAR = 'I'; const char AGENT_TYPE_AUDIO_MIXER = 'M'; const char AGENT_TYPE_AVATAR_MIXER = 'W'; diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index f40c8abea7..89f6fbaf54 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -32,7 +32,7 @@ const PACKET_HEADER PACKET_HEADER_AVATAR_VOXEL_URL = 'U'; const PACKET_HEADER PACKET_HEADER_TRANSMITTER_DATA_V2 = 'T'; const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e'; const PACKET_HEADER PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L'; -const PACKET_HEADER PACKET_HEADER_DOMAIN_RFD = 'C'; +const PACKET_HEADER PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY = 'C'; // These are supported Z-Command From fc27c2c7bb0c05a7f7e9249b59180f22d781d468 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 14:14:13 -0700 Subject: [PATCH 02/71] more renaming for AGENT_TYPE_VOXEL_SERVER --- interface/src/Application.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index acb82412ca..a0bf0ef705 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -418,7 +418,7 @@ static void sendVoxelServerAddScene() { char message[100]; sprintf(message,"%c%s",'Z',"add scene"); int messageSize = strlen(message) + 1; - AgentList::getInstance()->broadcastToAgents((unsigned char*)message, messageSize, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents((unsigned char*)message, messageSize, &AGENT_TYPE_VOXEL_SERVER, 1); } void Application::keyPressEvent(QKeyEvent* event) { @@ -1150,7 +1150,7 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { int sizeOut; if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, sizeOut)){ - AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(bufferOut, sizeOut, &AGENT_TYPE_VOXEL_SERVER, 1); delete[] bufferOut; } } @@ -1219,7 +1219,7 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { // if we have room don't have room in the buffer, then send the previously generated message first if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { - AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL_SERVER, 1); args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset } @@ -1283,7 +1283,7 @@ void Application::importVoxels() { // If we have voxels left in the packet, then send the packet if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { - AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL_SERVER, 1); } if (calculatedOctCode) { @@ -1335,7 +1335,7 @@ void Application::pasteVoxels() { // If we have voxels left in the packet, then send the packet if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { - AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); + AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL_SERVER, 1); } if (calculatedOctCode) { @@ -1624,7 +1624,7 @@ void Application::updateAvatar(float deltaTime) { endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite); - const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL, AGENT_TYPE_AVATAR_MIXER}; + const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL_SERVER, AGENT_TYPE_AVATAR_MIXER}; AgentList::getInstance()->broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, broadcastReceivers, sizeof(broadcastReceivers)); // once in a while, send my voxel url From 17750bd5d2c63d29d65bd0cb386332ec2e2030d5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 15:00:33 -0700 Subject: [PATCH 03/71] remove ShareAudioFactors struct from audio-mixer --- audio-mixer/src/main.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 7276a24594..718dae9757 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -70,11 +70,6 @@ void attachNewBufferToAgent(Agent *newAgent) { } } -struct SharedAudioFactors { - float distanceCoefficient; - float effectMix; -}; - int main(int argc, const char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); From 1e05936aead35efad9d1a93e4c9f4b4ae97de053 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 15:19:12 -0700 Subject: [PATCH 04/71] unthread DS check in, allow agents to tell DS who they want to hear about --- domain-server/src/main.cpp | 14 +++- interface/src/Application.cpp | 8 +- libraries/shared/src/AgentList.cpp | 120 +++++++++++++++-------------- libraries/shared/src/AgentList.h | 32 ++++---- libraries/shared/src/AgentTypes.h | 15 ++-- 5 files changed, 105 insertions(+), 84 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index b38ae5b824..da4852c4d9 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -102,7 +102,7 @@ int main(int argc, const char * argv[]) std::map newestSoloAgents; agentType = packetData[1]; - unpackSocket(packetData + 2, (sockaddr*) &agentLocalAddress); + int numBytesSocket = unpackSocket(packetData + 2, (sockaddr*) &agentLocalAddress); // check the agent public address // if it matches our local address we're on the same box @@ -124,11 +124,19 @@ int main(int argc, const char * argv[]) agentList->increaseAgentID(); } - currentBufferPos = broadcastPacket + 1; + currentBufferPos = broadcastPacket + sizeof(PACKET_HEADER); startPointer = currentBufferPos; + char* agentTypesOfInterest = (char*) currentBufferPos + sizeof(AGENT_TYPE) + numBytesSocket; + int numInterestTypes = strlen(agentTypesOfInterest); + for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType)) { + if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType) + && (numInterestTypes > 0 && memchr(agentTypesOfInterest, agent->getType(), strlen(agentTypesOfInterest)))) { + // this is not the agent themselves + // and this is an agent of a type in the passed agent types of interest + // or the agent did not pass us any specific types they are interested in + if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) { // this is an agent of which there can be multiple, just add them to the packet // don't send avatar agents to other avatars, that will come from avatar mixer diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a0bf0ef705..fe65c56424 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -207,10 +207,13 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : WSADATA WsaData; int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData); #endif + + // tell the AgentList instance who to tell the domain server we care about + const unsigned char agentTypesOfInterest[] = {AGENT_TYPE_AUDIO_MIXER, AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_VOXEL_SERVER}; + AgentList::getInstance()->setAgentTypesOfInterest(agentTypesOfInterest, sizeof(agentTypesOfInterest)); // start the agentList threads AgentList::getInstance()->startSilentAgentRemovalThread(); - AgentList::getInstance()->startDomainServerCheckInThread(); AgentList::getInstance()->startPingUnknownAgentsThread(); _window->setCentralWidget(_glWidget); @@ -749,6 +752,9 @@ void Application::timer() { if (!_serialHeadSensor.active) { _serialHeadSensor.pair(); } + + // ask the agent list to check in with the domain server + AgentList::getInstance()->sendDomainServerCheckIn(); } static glm::vec3 getFaceVector(BoxFace face) { diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 53aad60cd3..982116b39a 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -34,7 +34,6 @@ char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup const int DOMAINSERVER_PORT = 40102; bool silentAgentThreadStopFlag = false; -bool domainServerCheckinStopFlag = false; bool pingUnknownAgentThreadStopFlag = false; AgentList* AgentList::_sharedInstance = NULL; @@ -62,6 +61,7 @@ AgentList::AgentList(char newOwnerType, unsigned int newSocketListenPort) : _numAgents(0), _agentSocket(newSocketListenPort), _ownerType(newOwnerType), + _agentTypesOfInterest(NULL), _socketListenPort(newSocketListenPort), _ownerID(UNKNOWN_AGENT_ID), _lastAgentID(0) { @@ -69,9 +69,10 @@ AgentList::AgentList(char newOwnerType, unsigned int newSocketListenPort) : } AgentList::~AgentList() { + delete _agentTypesOfInterest; + // stop the spawned threads, if they were started stopSilentAgentRemovalThread(); - stopDomainServerCheckInThread(); stopPingUnknownAgentsThread(); pthread_mutex_destroy(&mutex); @@ -177,6 +178,65 @@ Agent* AgentList::agentWithID(uint16_t agentID) { return NULL; } +void AgentList::setAgentTypesOfInterest(const unsigned char* agentTypesOfInterest, int numAgentTypesOfInterest) { + delete _agentTypesOfInterest; + + _agentTypesOfInterest = new unsigned char[numAgentTypesOfInterest + sizeof(char)]; + memcpy(_agentTypesOfInterest, agentTypesOfInterest, numAgentTypesOfInterest); + _agentTypesOfInterest[numAgentTypesOfInterest] = '\0'; +} + +void AgentList::sendDomainServerCheckIn() { + static bool printedDomainServerIP = false; + // Lookup the IP address of the domain server if we need to + if (atoi(DOMAIN_IP) == 0) { + struct hostent* pHostInfo; + if ((pHostInfo = gethostbyname(DOMAIN_HOSTNAME)) != NULL) { + sockaddr_in tempAddress; + memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); + strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr)); + printLog("Domain Server: %s \n", DOMAIN_HOSTNAME); + } else { + printLog("Failed domain server lookup\n"); + } + } else if (!printedDomainServerIP) { + printLog("Domain Server IP: %s\n", DOMAIN_IP); + printedDomainServerIP = true; + } + + // construct the DS check in packet if we need to + static unsigned char* checkInPacket = NULL; + + if (!checkInPacket) { + int numBytesAgentsOfInterest = _agentTypesOfInterest ? strlen((char*) _agentTypesOfInterest) : NULL; + printf("There are %d AOI\n", numBytesAgentsOfInterest); + // check in packet has header, agent type, port, IP, agent types of interest, null termination + int numPacketBytes = sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE) + sizeof(uint16_t) + (sizeof(char) * 4) + + numBytesAgentsOfInterest + sizeof(char); + printf("Packet as a whole will be %d\n", numPacketBytes); + + checkInPacket = new unsigned char[numPacketBytes]; + + checkInPacket[0] = (memchr(SOLO_AGENT_TYPES, _ownerType, sizeof(SOLO_AGENT_TYPES))) + ? PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY + : PACKET_HEADER_DOMAIN_LIST_REQUEST; + checkInPacket[1] = _ownerType; + + packSocket(checkInPacket + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE), getLocalAddress(), htons(_socketListenPort)); + + // copy over the bytes for agent types of interest, if required + if (numBytesAgentsOfInterest > 0) { + memcpy(checkInPacket + numPacketBytes - sizeof(char) - numBytesAgentsOfInterest, + _agentTypesOfInterest, + numBytesAgentsOfInterest); + } + + checkInPacket[numPacketBytes - 1] = '\0'; + } + + _agentSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, strlen((char*) checkInPacket)); +} + int AgentList::processDomainServerList(unsigned char *packetData, size_t dataBytes) { int readAgents = 0; @@ -388,62 +448,6 @@ void AgentList::stopSilentAgentRemovalThread() { pthread_join(removeSilentAgentsThread, NULL); } -void *checkInWithDomainServer(void *args) { - - const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; - - // Lookup the IP address of the domain server if we need to - if (atoi(DOMAIN_IP) == 0) { - struct hostent* pHostInfo; - if ((pHostInfo = gethostbyname(DOMAIN_HOSTNAME)) != NULL) { - sockaddr_in tempAddress; - memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); - strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr)); - printLog("Domain Server: %s \n", DOMAIN_HOSTNAME); - - } else { - printLog("Failed lookup domainserver\n"); - } - } else printLog("Domain Server IP: %s\n", DOMAIN_IP); - - AgentList* parentAgentList = (AgentList*) args; - - timeval lastSend; - in_addr_t localAddress = getLocalAddress(); - unsigned char packet[8]; - - packet[0] = PACKET_HEADER_DOMAIN_RFD; - packet[1] = parentAgentList->getOwnerType(); - - while (!domainServerCheckinStopFlag) { - gettimeofday(&lastSend, NULL); - - packSocket(packet + 2, localAddress, htons(parentAgentList->getSocketListenPort())); - - parentAgentList->getAgentSocket()->send(DOMAIN_IP, DOMAINSERVER_PORT, packet, sizeof(packet)); - - packet[0] = PACKET_HEADER_DOMAIN_LIST_REQUEST; - - double usecToSleep = DOMAIN_SERVER_CHECK_IN_USECS - (usecTimestampNow() - usecTimestamp(&lastSend)); - - if (usecToSleep > 0) { - usleep(usecToSleep); - } - } - - pthread_exit(0); - return NULL; -} - -void AgentList::startDomainServerCheckInThread() { - pthread_create(&checkInWithDomainServerThread, NULL, checkInWithDomainServer, (void*) this); -} - -void AgentList::stopDomainServerCheckInThread() { - domainServerCheckinStopFlag = true; - pthread_join(checkInWithDomainServerThread, NULL); -} - AgentList::iterator AgentList::begin() const { Agent** agentBucket = NULL; diff --git a/libraries/shared/src/AgentList.h b/libraries/shared/src/AgentList.h index e5db88569c..2c07b7c34f 100644 --- a/libraries/shared/src/AgentList.h +++ b/libraries/shared/src/AgentList.h @@ -26,6 +26,8 @@ const int MAX_PACKET_SIZE = 1500; const unsigned int AGENT_SOCKET_LISTEN_PORT = 40103; const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000; +const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; + extern const char SOLO_AGENT_TYPES[3]; extern char DOMAIN_HOSTNAME[]; @@ -46,6 +48,18 @@ public: AgentListIterator begin() const; AgentListIterator end() const; + char getOwnerType() const { return _ownerType; } + + uint16_t getLastAgentID() const { return _lastAgentID; } + void increaseAgentID() { ++_lastAgentID; } + + uint16_t getOwnerID() const { return _ownerID; } + void setOwnerID(uint16_t ownerID) { _ownerID = ownerID; } + + UDPSocket* getAgentSocket() { return &_agentSocket; } + + unsigned int getSocketListenPort() const { return _socketListenPort; }; + void(*linkedDataCreateCallback)(Agent *); int size() { return _numAgents; } @@ -53,6 +67,8 @@ public: void lock() { pthread_mutex_lock(&mutex); } void unlock() { pthread_mutex_unlock(&mutex); } + void setAgentTypesOfInterest(const unsigned char* agentTypesOfInterest, int numAgentTypesOfInterest); + void sendDomainServerCheckIn(); int processDomainServerList(unsigned char *packetData, size_t dataBytes); Agent* agentWithAddress(sockaddr *senderAddress); @@ -67,26 +83,11 @@ public: int updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes); void broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes); - unsigned int getSocketListenPort(); - - char getOwnerType() const { return _ownerType; } - - uint16_t getLastAgentID() const { return _lastAgentID; } - void increaseAgentID() { ++_lastAgentID; } - - uint16_t getOwnerID() const { return _ownerID; } - void setOwnerID(uint16_t ownerID) { _ownerID = ownerID; } - - UDPSocket* getAgentSocket() { return &_agentSocket; } - - unsigned int getSocketListenPort() const { return _socketListenPort; }; Agent* soloAgentOfType(char agentType); void startSilentAgentRemovalThread(); void stopSilentAgentRemovalThread(); - void startDomainServerCheckInThread(); - void stopDomainServerCheckInThread(); void startPingUnknownAgentsThread(); void stopPingUnknownAgentsThread(); @@ -105,6 +106,7 @@ private: int _numAgents; UDPSocket _agentSocket; char _ownerType; + unsigned char* _agentTypesOfInterest; unsigned int _socketListenPort; uint16_t _ownerID; uint16_t _lastAgentID; diff --git a/libraries/shared/src/AgentTypes.h b/libraries/shared/src/AgentTypes.h index 8bc97b5ba3..56e900c923 100644 --- a/libraries/shared/src/AgentTypes.h +++ b/libraries/shared/src/AgentTypes.h @@ -16,12 +16,13 @@ // If you don't then it will make things harder on your co-developers in debugging because the Agent // class won't know the name and will report it as "Unknown". -const char AGENT_TYPE_DOMAIN = 'D'; -const char AGENT_TYPE_VOXEL_SERVER = 'V'; -const char AGENT_TYPE_AVATAR = 'I'; -const char AGENT_TYPE_AUDIO_MIXER = 'M'; -const char AGENT_TYPE_AVATAR_MIXER = 'W'; -const char AGENT_TYPE_AUDIO_INJECTOR = 'A'; -const char AGENT_TYPE_ANIMATION_SERVER = 'a'; +typedef char AGENT_TYPE; +const AGENT_TYPE AGENT_TYPE_DOMAIN = 'D'; +const AGENT_TYPE AGENT_TYPE_VOXEL_SERVER = 'V'; +const AGENT_TYPE AGENT_TYPE_AVATAR = 'I'; +const AGENT_TYPE AGENT_TYPE_AUDIO_MIXER = 'M'; +const AGENT_TYPE AGENT_TYPE_AVATAR_MIXER = 'W'; +const AGENT_TYPE AGENT_TYPE_AUDIO_INJECTOR = 'A'; +const AGENT_TYPE AGENT_TYPE_ANIMATION_SERVER = 'a'; #endif From 8c30c3ff7f8145fc127c464793fee8d62e5dcea2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 15:20:43 -0700 Subject: [PATCH 05/71] use new non-threaded method to checkin with domain server --- animation-server/src/main.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index 9878d2e6a4..3134488157 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -702,7 +702,6 @@ int main(int argc, const char * argv[]) agentList->linkedDataCreateCallback = NULL; // do we need a callback? agentList->startSilentAgentRemovalThread(); - agentList->startDomainServerCheckInThread(); srand((unsigned)time(0)); @@ -713,16 +712,20 @@ int main(int argc, const char * argv[]) unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; ssize_t receivedBytes; + + timeval lastDomainServerCheckIn = {}; // loop to send to agents requesting data while (true) { - // Agents sending messages to us... + // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed + if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { + gettimeofday(&lastDomainServerCheckIn, NULL); + AgentList::getInstance()->sendDomainServerCheckIn(); + } + + // Agents sending messages to us... if (agentList->getAgentSocket()->receive(&agentPublicAddress, packetData, &receivedBytes)) { - switch (packetData[0]) { - default: { - AgentList::getInstance()->processAgentData(&agentPublicAddress, packetData, receivedBytes); - } break; - } + AgentList::getInstance()->processAgentData(&agentPublicAddress, packetData, receivedBytes); } } From d33f3e43bd46ccf3a19ff150a8d5a1c45e112b74 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 15:28:30 -0700 Subject: [PATCH 06/71] agentTypesOfInterest need not be unsigned and remove debugging --- libraries/shared/src/AgentList.cpp | 7 +++---- libraries/shared/src/AgentList.h | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 982116b39a..6f38bff519 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -178,10 +178,10 @@ Agent* AgentList::agentWithID(uint16_t agentID) { return NULL; } -void AgentList::setAgentTypesOfInterest(const unsigned char* agentTypesOfInterest, int numAgentTypesOfInterest) { +void AgentList::setAgentTypesOfInterest(const char* agentTypesOfInterest, int numAgentTypesOfInterest) { delete _agentTypesOfInterest; - _agentTypesOfInterest = new unsigned char[numAgentTypesOfInterest + sizeof(char)]; + _agentTypesOfInterest = new char[numAgentTypesOfInterest + sizeof(char)]; memcpy(_agentTypesOfInterest, agentTypesOfInterest, numAgentTypesOfInterest); _agentTypesOfInterest[numAgentTypesOfInterest] = '\0'; } @@ -209,11 +209,10 @@ void AgentList::sendDomainServerCheckIn() { if (!checkInPacket) { int numBytesAgentsOfInterest = _agentTypesOfInterest ? strlen((char*) _agentTypesOfInterest) : NULL; - printf("There are %d AOI\n", numBytesAgentsOfInterest); + // check in packet has header, agent type, port, IP, agent types of interest, null termination int numPacketBytes = sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE) + sizeof(uint16_t) + (sizeof(char) * 4) + numBytesAgentsOfInterest + sizeof(char); - printf("Packet as a whole will be %d\n", numPacketBytes); checkInPacket = new unsigned char[numPacketBytes]; diff --git a/libraries/shared/src/AgentList.h b/libraries/shared/src/AgentList.h index 2c07b7c34f..3007dbc8e3 100644 --- a/libraries/shared/src/AgentList.h +++ b/libraries/shared/src/AgentList.h @@ -67,7 +67,7 @@ public: void lock() { pthread_mutex_lock(&mutex); } void unlock() { pthread_mutex_unlock(&mutex); } - void setAgentTypesOfInterest(const unsigned char* agentTypesOfInterest, int numAgentTypesOfInterest); + void setAgentTypesOfInterest(const char* agentTypesOfInterest, int numAgentTypesOfInterest); void sendDomainServerCheckIn(); int processDomainServerList(unsigned char *packetData, size_t dataBytes); @@ -106,7 +106,7 @@ private: int _numAgents; UDPSocket _agentSocket; char _ownerType; - unsigned char* _agentTypesOfInterest; + char* _agentTypesOfInterest; unsigned int _socketListenPort; uint16_t _ownerID; uint16_t _lastAgentID; From 4715dbf412663b5ddd18488655e50d5b6a55d9fe Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 15:29:26 -0700 Subject: [PATCH 07/71] ask only for agents of type AGENT_TYPE_VOXEL_SERVER --- animation-server/src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index 3134488157..c02e8e8383 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -714,6 +714,7 @@ int main(int argc, const char * argv[]) ssize_t receivedBytes; timeval lastDomainServerCheckIn = {}; + AgentList::getInstance()->setAgentTypesOfInterest(&AGENT_TYPE_VOXEL_SERVER, 1); // loop to send to agents requesting data while (true) { From 0585d6756de1a35b106cb2bdad3fcf72b3d8f49b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 15:34:30 -0700 Subject: [PATCH 08/71] if an agent doesn't send a list of types of interest assume it wants to hear about nobody --- domain-server/src/main.cpp | 77 ++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index da4852c4d9..3bc40efc07 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -130,49 +130,52 @@ int main(int argc, const char * argv[]) char* agentTypesOfInterest = (char*) currentBufferPos + sizeof(AGENT_TYPE) + numBytesSocket; int numInterestTypes = strlen(agentTypesOfInterest); - for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType) - && (numInterestTypes > 0 && memchr(agentTypesOfInterest, agent->getType(), strlen(agentTypesOfInterest)))) { - // this is not the agent themselves - // and this is an agent of a type in the passed agent types of interest - // or the agent did not pass us any specific types they are interested in + if (numInterestTypes > 0) { + // if the agent has sent no types of interest, assume they want nothing but their own ID back + for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { + if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType) + && memchr(agentTypesOfInterest, agent->getType(), strlen(agentTypesOfInterest))) { + // this is not the agent themselves + // and this is an agent of a type in the passed agent types of interest + // or the agent did not pass us any specific types they are interested in - if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) { - // this is an agent of which there can be multiple, just add them to the packet - // don't send avatar agents to other avatars, that will come from avatar mixer - if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) { - currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent)); + if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) { + // this is an agent of which there can be multiple, just add them to the packet + // don't send avatar agents to other avatars, that will come from avatar mixer + if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) { + currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent)); + } + + } else { + // solo agent, we need to only send newest + if (newestSoloAgents[agent->getType()] == NULL || + newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) { + // we have to set the newer solo agent to add it to the broadcast later + newestSoloAgents[agent->getType()] = &(*agent); + } } - } else { - // solo agent, we need to only send newest - if (newestSoloAgents[agent->getType()] == NULL || - newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) { - // we have to set the newer solo agent to add it to the broadcast later - newestSoloAgents[agent->getType()] = &(*agent); - } - } - } else { - double timeNow = usecTimestampNow(); - - // this is the agent, just update last receive to now - agent->setLastHeardMicrostamp(timeNow); - - // grab the ID for this agent so we can send it back with the packet - packetAgentID = agent->getAgentID(); - - if (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY - && memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) { + double timeNow = usecTimestampNow(); + + // this is the agent, just update last receive to now + agent->setLastHeardMicrostamp(timeNow); + + // grab the ID for this agent so we can send it back with the packet + packetAgentID = agent->getAgentID(); + + if (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY + && memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) { agent->setWakeMicrostamp(timeNow); + } } } - } - - for (std::map::iterator soloAgent = newestSoloAgents.begin(); - soloAgent != newestSoloAgents.end(); - soloAgent++) { - // this is the newest alive solo agent, add them to the packet - currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, soloAgent->second); + + for (std::map::iterator soloAgent = newestSoloAgents.begin(); + soloAgent != newestSoloAgents.end(); + soloAgent++) { + // this is the newest alive solo agent, add them to the packet + currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, soloAgent->second); + } } // add the agent ID to the end of the pointer From d95d3eba3b979cf6453881ad6cf8f183283e5661 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 15:35:17 -0700 Subject: [PATCH 09/71] hook audio-mixer up to new domain server check in method --- audio-mixer/src/main.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 718dae9757..c9ea474354 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -80,7 +80,6 @@ int main(int argc, const char* argv[]) { agentList->linkedDataCreateCallback = attachNewBufferToAgent; agentList->startSilentAgentRemovalThread(); - agentList->startDomainServerCheckInThread(); unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; @@ -99,7 +98,16 @@ int main(int argc, const char* argv[]) { gettimeofday(&startTime, NULL); + timeval lastDomainServerCheckIn = {}; + while (true) { + + // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed + if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { + gettimeofday(&lastDomainServerCheckIn, NULL); + AgentList::getInstance()->sendDomainServerCheckIn(); + } + for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { PositionalAudioRingBuffer* positionalRingBuffer = (PositionalAudioRingBuffer*) agent->getLinkedData(); From dae8032cd8c52123d909c0e13dad84e1ff57585b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 15:35:33 -0700 Subject: [PATCH 10/71] hook the avatar mixer up to the new domain server check in method --- avatar-mixer/src/main.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/avatar-mixer/src/main.cpp b/avatar-mixer/src/main.cpp index 0398a597fc..aace967564 100644 --- a/avatar-mixer/src/main.cpp +++ b/avatar-mixer/src/main.cpp @@ -66,7 +66,6 @@ int main(int argc, const char* argv[]) { agentList->linkedDataCreateCallback = attachAvatarDataToAgent; - agentList->startDomainServerCheckInThread(); agentList->startSilentAgentRemovalThread(); sockaddr *agentAddress = new sockaddr; @@ -80,8 +79,19 @@ int main(int argc, const char* argv[]) { uint16_t agentID = 0; Agent* avatarAgent = NULL; - + + timeval lastDomainServerCheckIn = {}; + // we only need to hear back about avatar agents from the DS + AgentList::getInstance()->setAgentTypesOfInterest(&AGENT_TYPE_AVATAR, 1); + while (true) { + + // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed + if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { + gettimeofday(&lastDomainServerCheckIn, NULL); + AgentList::getInstance()->sendDomainServerCheckIn(); + } + if (agentList->getAgentSocket()->receive(agentAddress, packetData, &receivedBytes)) { switch (packetData[0]) { case PACKET_HEADER_HEAD_DATA: @@ -129,7 +139,6 @@ int main(int argc, const char* argv[]) { } agentList->stopSilentAgentRemovalThread(); - agentList->stopDomainServerCheckInThread(); return 0; } From 5efff3857a07176763e3755cde95cffd0a696572 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 7 Jun 2013 15:39:46 -0700 Subject: [PATCH 11/71] hook eve up to new domain server check in method --- eve/src/main.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/eve/src/main.cpp b/eve/src/main.cpp index c670be050e..387c72633b 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -82,9 +82,6 @@ int main(int argc, const char* argv[]) { // create an AgentList instance to handle communication with other agents AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LISTEN_PORT); - // start telling the domain server that we are alive - agentList->startDomainServerCheckInThread(); - // start the agent list thread that will kill off agents when they stop talking agentList->startSilentAgentRemovalThread(); @@ -134,8 +131,20 @@ int main(int argc, const char* argv[]) { double numMicrosecondsSleep = 0; int handStateTimer = 0; + + timeval lastDomainServerCheckIn = {}; + + // eve wants to hear about an avatar mixer and an audio mixer from the domain server + const char EVE_AGENT_TYPES_OF_INTEREST[] = {AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_AUDIO_MIXER}; + AgentList::getInstance()->setAgentTypesOfInterest(EVE_AGENT_TYPES_OF_INTEREST, sizeof(EVE_AGENT_TYPES_OF_INTEREST)); while (true) { + // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed + if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { + gettimeofday(&lastDomainServerCheckIn, NULL); + AgentList::getInstance()->sendDomainServerCheckIn(); + } + // update the thisSend timeval to the current time gettimeofday(&thisSend, NULL); @@ -201,7 +210,6 @@ int main(int argc, const char* argv[]) { pthread_join(receiveAgentDataThread, NULL); // stop the agent list's threads - agentList->stopDomainServerCheckInThread(); agentList->stopPingUnknownAgentsThread(); agentList->stopSilentAgentRemovalThread(); } \ No newline at end of file From 297a78188af622d3fae3dc5f8bb6dbf4746f7919 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 10 Jun 2013 08:10:51 -0700 Subject: [PATCH 12/71] removed const values per code review --- libraries/voxels/src/VoxelNode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 952ad15bb7..58776755fa 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -103,8 +103,8 @@ public: void setColor(const nodeColor& color); const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _currentColor; }; - void setDensity(const float density) { _density = density; }; - const float getDensity() const { return _density; }; + void setDensity(float density) { _density = density; }; + float getDensity() const { return _density; }; #else void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ }; void setFalseColored(bool isFalseColored) { /* no op */ }; From ed79a9f72aff5c8c598a38f4146d2c859df0bd48 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Jun 2013 12:18:25 -0700 Subject: [PATCH 13/71] prepend the agent types of interest with the number that follow --- domain-server/src/main.cpp | 6 +++--- libraries/shared/src/AgentList.cpp | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 3bc40efc07..6988137455 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -127,14 +127,14 @@ int main(int argc, const char * argv[]) currentBufferPos = broadcastPacket + sizeof(PACKET_HEADER); startPointer = currentBufferPos; - char* agentTypesOfInterest = (char*) currentBufferPos + sizeof(AGENT_TYPE) + numBytesSocket; - int numInterestTypes = strlen(agentTypesOfInterest); + char* agentTypesOfInterest = (char*) currentBufferPos + sizeof(AGENT_TYPE) + numBytesSocket + sizeof(unsigned char); + int numInterestTypes = *(agentTypesOfInterest - 1); if (numInterestTypes > 0) { // if the agent has sent no types of interest, assume they want nothing but their own ID back for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType) - && memchr(agentTypesOfInterest, agent->getType(), strlen(agentTypesOfInterest))) { + && memchr(agentTypesOfInterest, agent->getType(), numInterestTypes)) { // this is not the agent themselves // and this is an agent of a type in the passed agent types of interest // or the agent did not pass us any specific types they are interested in diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 6f38bff519..1da6b90c2d 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -208,11 +208,11 @@ void AgentList::sendDomainServerCheckIn() { static unsigned char* checkInPacket = NULL; if (!checkInPacket) { - int numBytesAgentsOfInterest = _agentTypesOfInterest ? strlen((char*) _agentTypesOfInterest) : NULL; + int numBytesAgentsOfInterest = _agentTypesOfInterest ? strlen((char*) _agentTypesOfInterest) : 0; // check in packet has header, agent type, port, IP, agent types of interest, null termination int numPacketBytes = sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE) + sizeof(uint16_t) + (sizeof(char) * 4) + - numBytesAgentsOfInterest + sizeof(char); + numBytesAgentsOfInterest + sizeof(unsigned char); checkInPacket = new unsigned char[numPacketBytes]; @@ -223,14 +223,15 @@ void AgentList::sendDomainServerCheckIn() { packSocket(checkInPacket + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE), getLocalAddress(), htons(_socketListenPort)); + // add the number of bytes for agent types of interest + checkInPacket[numPacketBytes] = numBytesAgentsOfInterest; + // copy over the bytes for agent types of interest, if required if (numBytesAgentsOfInterest > 0) { - memcpy(checkInPacket + numPacketBytes - sizeof(char) - numBytesAgentsOfInterest, + memcpy(checkInPacket + numPacketBytes + sizeof(unsigned char), _agentTypesOfInterest, numBytesAgentsOfInterest); } - - checkInPacket[numPacketBytes - 1] = '\0'; } _agentSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, strlen((char*) checkInPacket)); From 7fb42dcb8a089549e01d636040215e9a797c58ce Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Jun 2013 13:48:34 -0700 Subject: [PATCH 14/71] fix bug with sent and received agent interest packets --- domain-server/src/main.cpp | 6 ++++-- interface/src/Application.cpp | 2 +- libraries/shared/src/AgentList.cpp | 16 +++++++++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 6988137455..b1e2117db3 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -102,7 +102,8 @@ int main(int argc, const char * argv[]) std::map newestSoloAgents; agentType = packetData[1]; - int numBytesSocket = unpackSocket(packetData + 2, (sockaddr*) &agentLocalAddress); + int numBytesSocket = unpackSocket(packetData + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE), + (sockaddr*) &agentLocalAddress); // check the agent public address // if it matches our local address we're on the same box @@ -127,7 +128,8 @@ int main(int argc, const char * argv[]) currentBufferPos = broadcastPacket + sizeof(PACKET_HEADER); startPointer = currentBufferPos; - char* agentTypesOfInterest = (char*) currentBufferPos + sizeof(AGENT_TYPE) + numBytesSocket + sizeof(unsigned char); + unsigned char* agentTypesOfInterest = packetData + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE) + + numBytesSocket + sizeof(unsigned char); int numInterestTypes = *(agentTypesOfInterest - 1); if (numInterestTypes > 0) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe65c56424..df9321a977 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -209,7 +209,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : #endif // tell the AgentList instance who to tell the domain server we care about - const unsigned char agentTypesOfInterest[] = {AGENT_TYPE_AUDIO_MIXER, AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_VOXEL_SERVER}; + const char agentTypesOfInterest[] = {AGENT_TYPE_AUDIO_MIXER, AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_VOXEL_SERVER}; AgentList::getInstance()->setAgentTypesOfInterest(agentTypesOfInterest, sizeof(agentTypesOfInterest)); // start the agentList threads diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 1da6b90c2d..42a735a1e3 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -215,23 +215,29 @@ void AgentList::sendDomainServerCheckIn() { numBytesAgentsOfInterest + sizeof(unsigned char); checkInPacket = new unsigned char[numPacketBytes]; + unsigned char* packetPosition = checkInPacket; - checkInPacket[0] = (memchr(SOLO_AGENT_TYPES, _ownerType, sizeof(SOLO_AGENT_TYPES))) + *(packetPosition++) = (memchr(SOLO_AGENT_TYPES, _ownerType, sizeof(SOLO_AGENT_TYPES))) ? PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY : PACKET_HEADER_DOMAIN_LIST_REQUEST; - checkInPacket[1] = _ownerType; + *(packetPosition++) = _ownerType; - packSocket(checkInPacket + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE), getLocalAddress(), htons(_socketListenPort)); + packetPosition += packSocket(checkInPacket + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE), + getLocalAddress(), + htons(_socketListenPort)); // add the number of bytes for agent types of interest - checkInPacket[numPacketBytes] = numBytesAgentsOfInterest; + *(packetPosition++) = numBytesAgentsOfInterest; // copy over the bytes for agent types of interest, if required if (numBytesAgentsOfInterest > 0) { - memcpy(checkInPacket + numPacketBytes + sizeof(unsigned char), + memcpy(packetPosition, _agentTypesOfInterest, numBytesAgentsOfInterest); + packetPosition += numBytesAgentsOfInterest; } + + *packetPosition = '\0'; } _agentSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, strlen((char*) checkInPacket)); From 2e99ae199ee0e93364731dafcdea8d8421111aed Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Jun 2013 13:48:51 -0700 Subject: [PATCH 15/71] hook injector up to new domain-server interest list --- injector/src/main.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 41e2bc0bbd..f2e87990d1 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -167,9 +167,6 @@ int main(int argc, char* argv[]) { pthread_t receiveAgentDataThread; pthread_create(&receiveAgentDataThread, NULL, receiveAgentData, NULL); - // start telling the domain server that we are alive - agentList->startDomainServerCheckInThread(); - // start the agent list thread that will kill off agents when they stop talking agentList->startSilentAgentRemovalThread(); @@ -192,7 +189,20 @@ int main(int argc, char* argv[]) { timeval thisSend; double numMicrosecondsSleep = 0; + timeval lastDomainServerCheckIn = {}; + + // the audio injector needs to know about the avatar mixer and the audio mixer + const char INJECTOR_AGENTS_OF_INTEREST[] = {AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_AUDIO_MIXER}; + AgentList::getInstance()->setAgentTypesOfInterest(INJECTOR_AGENTS_OF_INTEREST, sizeof(INJECTOR_AGENTS_OF_INTEREST)); + while (true) { + + // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed + if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { + gettimeofday(&lastDomainServerCheckIn, NULL); + AgentList::getInstance()->sendDomainServerCheckIn(); + } + if (::triggerDistance) { // update the thisSend timeval to the current time @@ -260,7 +270,6 @@ int main(int argc, char* argv[]) { pthread_join(receiveAgentDataThread, NULL); // stop the agent list's threads - agentList->stopDomainServerCheckInThread(); agentList->stopSilentAgentRemovalThread(); } } From ae0ef412a326576e28f3f70c36febd3c4c61979e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Jun 2013 13:54:18 -0700 Subject: [PATCH 16/71] hook up voxel-server to domain-server interest list --- voxel-server/src/main.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 81a92d4d07..2d6cd4d991 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -460,7 +460,7 @@ int main(int argc, const char * argv[]) { pthread_mutex_init(&::treeLock, NULL); - AgentList* agentList = AgentList::createInstance(AGENT_TYPE_VOXEL, VOXEL_LISTEN_PORT); + AgentList* agentList = AgentList::createInstance(AGENT_TYPE_VOXEL_SERVER, VOXEL_LISTEN_PORT); setvbuf(stdout, NULL, _IOLBF, 0); // Handle Local Domain testing with the --local command line @@ -474,7 +474,6 @@ int main(int argc, const char * argv[]) { agentList->linkedDataCreateCallback = &attachVoxelAgentDataToAgent; agentList->startSilentAgentRemovalThread(); - agentList->startDomainServerCheckInThread(); srand((unsigned)time(0)); @@ -577,10 +576,19 @@ int main(int argc, const char * argv[]) { unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE]; ssize_t receivedBytes; + + timeval lastDomainServerCheckIn = {}; // loop to send to agents requesting data - while (true) { + while (true) { + + // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed + if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { + gettimeofday(&lastDomainServerCheckIn, NULL); + AgentList::getInstance()->sendDomainServerCheckIn(); + } + // check to see if we need to persist our voxel state persistVoxelsWhenDirty(); From b15f5a721b460160ba0b189aff6210283b432e34 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 10 Jun 2013 14:03:34 -0700 Subject: [PATCH 17/71] remove hacked method to keep servers alive --- libraries/shared/src/AgentList.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 42a735a1e3..9c309bb23f 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -309,9 +309,7 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket } else { if (agent->getType() == AGENT_TYPE_AUDIO_MIXER || - agent->getType() == AGENT_TYPE_VOXEL_SERVER || - agent->getType() == AGENT_TYPE_ANIMATION_SERVER || - agent->getType() == AGENT_TYPE_AUDIO_INJECTOR) { + agent->getType() == AGENT_TYPE_VOXEL_SERVER) { // until the Audio class also uses our agentList, we need to update // the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously agent->setLastHeardMicrostamp(usecTimestampNow()); From 5820c3c7c33de16ed8e8d81c7257dc1f924e2df6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Jun 2013 14:49:39 -0700 Subject: [PATCH 18/71] Remove average measurements, compute estimated acceleration (without rotated gravity). --- interface/src/SerialInterface.cpp | 23 ++++++++--------------- interface/src/SerialInterface.h | 12 +++++------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 28ae7eceb4..aca91bb34b 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -155,11 +155,11 @@ void SerialInterface::renderLevels(int width, int height) { // Acceleration rates glColor4f(1, 1, 1, 1); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 42); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)((_lastAcceleration.x - _gravity.x) *ACCEL_VIEW_SCALING), LEVEL_CORNER_Y + 42); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_estimatedAcceleration.x * ACCEL_VIEW_SCALING), LEVEL_CORNER_Y + 42); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 57); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)((_lastAcceleration.y - _gravity.y) *ACCEL_VIEW_SCALING), LEVEL_CORNER_Y + 57); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_estimatedAcceleration.y * ACCEL_VIEW_SCALING), LEVEL_CORNER_Y + 57); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 72); - glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)((_lastAcceleration.z - _gravity.z) * ACCEL_VIEW_SCALING), LEVEL_CORNER_Y + 72); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_estimatedAcceleration.z * ACCEL_VIEW_SCALING), LEVEL_CORNER_Y + 72); // Estimated Position glColor4f(0, 1, 1, 1); @@ -231,29 +231,24 @@ void SerialInterface::readData(float deltaTime) { // Update raw rotation estimates glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) * - glm::quat(glm::radians(deltaTime * (_lastRotationRates - _averageRotationRates))); + glm::quat(glm::radians(deltaTime * _lastRotationRates)); + + // Update acceleration estimate + _estimatedAcceleration = _lastAcceleration - glm::inverse(estimatedRotation) * _gravity; // Update estimated position and velocity float const DECAY_VELOCITY = 0.95f; float const DECAY_POSITION = 0.95f; - _estimatedVelocity += deltaTime * (_lastAcceleration - _averageAcceleration); + _estimatedVelocity += deltaTime * _estimatedAcceleration; _estimatedPosition += deltaTime * _estimatedVelocity; _estimatedVelocity *= DECAY_VELOCITY; _estimatedPosition *= DECAY_POSITION; // Accumulate a set of initial baseline readings for setting gravity if (totalSamples == 0) { - _averageRotationRates = _lastRotationRates; - _averageAcceleration = _lastAcceleration; _gravity = _lastAcceleration; } else { - // Cumulate long term average to (hopefully) take DC bias out of rotation rates - _averageRotationRates = (1.f - 1.f / (float)LONG_TERM_RATE_SAMPLES) * _averageRotationRates - + 1.f / (float)LONG_TERM_RATE_SAMPLES * _lastRotationRates; - _averageAcceleration = (1.f - 1.f / (float)LONG_TERM_RATE_SAMPLES) * _averageAcceleration - + 1.f / (float)LONG_TERM_RATE_SAMPLES * _lastAcceleration; - if (totalSamples < GRAVITY_SAMPLES) { _gravity = (1.f - 1.f/(float)GRAVITY_SAMPLES) * _gravity + 1.f/(float)GRAVITY_SAMPLES * _lastAcceleration; @@ -293,8 +288,6 @@ void SerialInterface::readData(float deltaTime) { void SerialInterface::resetAverages() { totalSamples = 0; _gravity = glm::vec3(0, 0, 0); - _averageRotationRates = glm::vec3(0, 0, 0); - _averageAcceleration = glm::vec3(0, 0, 0); _lastRotationRates = glm::vec3(0, 0, 0); _estimatedRotation = glm::vec3(0, 0, 0); _estimatedPosition = glm::vec3(0, 0, 0); diff --git a/interface/src/SerialInterface.h b/interface/src/SerialInterface.h index 3fc9ea920a..a49c09c599 100644 --- a/interface/src/SerialInterface.h +++ b/interface/src/SerialInterface.h @@ -26,8 +26,6 @@ class SerialInterface { public: SerialInterface() : active(false), _gravity(0, 0, 0), - _averageRotationRates(0, 0, 0), - _averageAcceleration(0, 0, 0), _estimatedRotation(0, 0, 0), _estimatedPosition(0, 0, 0), _estimatedVelocity(0, 0, 0), @@ -37,13 +35,14 @@ public: void pair(); void readData(float deltaTime); - const float getLastPitchRate() const { return _lastRotationRates[0] - _averageRotationRates[0]; } - const float getLastYawRate() const { return _lastRotationRates[1] - _averageRotationRates[1]; } - const float getLastRollRate() const { return _lastRotationRates[2] - _averageRotationRates[2]; } + const float getLastPitchRate() const { return _lastRotationRates[0]; } + const float getLastYawRate() const { return _lastRotationRates[1]; } + const float getLastRollRate() const { return _lastRotationRates[2]; } const glm::vec3& getLastRotationRates() const { return _lastRotationRates; }; const glm::vec3& getEstimatedRotation() const { return _estimatedRotation; }; const glm::vec3& getEstimatedPosition() const { return _estimatedPosition; }; const glm::vec3& getEstimatedVelocity() const { return _estimatedVelocity; }; + const glm::vec3& getEstimatedAcceleration() const { return _estimatedAcceleration; }; const glm::vec3& getLastAcceleration() const { return _lastAcceleration; }; const glm::vec3& getGravity() const { return _gravity; }; @@ -59,11 +58,10 @@ private: int totalSamples; timeval lastGoodRead; glm::vec3 _gravity; - glm::vec3 _averageRotationRates; - glm::vec3 _averageAcceleration; glm::vec3 _estimatedRotation; glm::vec3 _estimatedPosition; glm::vec3 _estimatedVelocity; + glm::vec3 _estimatedAcceleration; glm::vec3 _lastAcceleration; glm::vec3 _lastRotationRates; }; From 1b8683cbc5371b6603758c32bd9c667eba7e19a4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Jun 2013 15:22:53 -0700 Subject: [PATCH 19/71] Let's see if we can get an estimate of the distance to the sensor based on the ratios between linear and angular velocity. --- interface/src/SerialInterface.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index aca91bb34b..26c7f5f581 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -225,9 +225,14 @@ void SerialInterface::readData(float deltaTime) { // Convert the integer rates to floats const float LSB_TO_DEGREES_PER_SECOND = 1.f / 16.4f; // From MPU-9150 register map, 2000 deg/sec. - _lastRotationRates[0] = ((float) -pitchRate) * LSB_TO_DEGREES_PER_SECOND; - _lastRotationRates[1] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND; - _lastRotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND; + glm::vec3 rotationRates; + rotationRates[0] = ((float) -pitchRate) * LSB_TO_DEGREES_PER_SECOND; + rotationRates[1] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND; + rotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND; + + // compute the angular acceleration + glm::vec3 angularAcceleration = (deltaTime < EPSILON) ? glm::vec3() : (rotationRates - _lastRotationRates) / deltaTime; + _lastRotationRates = rotationRates; // Update raw rotation estimates glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) * @@ -236,6 +241,16 @@ void SerialInterface::readData(float deltaTime) { // Update acceleration estimate _estimatedAcceleration = _lastAcceleration - glm::inverse(estimatedRotation) * _gravity; + static float ratioEstimate = 0.0f; + float angularAccelerationLength = glm::length(angularAcceleration); + float linearAccelerationLength = glm::length(estimatedAcceleration); + if (angularAccelerationLength > EPSILON && linearAccelerationLength > EPSILON) { + float ratio = linearAccelerationLength / angularAccelerationLength; + static float ratioEstimate = ratio; + ratioEstimate = ratioEstimate * 0.999 + ratio * 0.001; + printLog("%g %g\n", ratio, ratioEstimate); + } + // Update estimated position and velocity float const DECAY_VELOCITY = 0.95f; float const DECAY_POSITION = 0.95f; From 90ef6a7cc0b3fe20d58b266d835ccdb27d08c713 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Jun 2013 18:40:07 -0700 Subject: [PATCH 20/71] Attempting to perform the transform between angular and linear acceleration. --- interface/src/SerialInterface.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 26c7f5f581..407f06f736 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -238,18 +238,19 @@ void SerialInterface::readData(float deltaTime) { glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) * glm::quat(glm::radians(deltaTime * _lastRotationRates)); + // The acceleration matrix transforms angular to linear accelerations + const glm::vec3 PIVOT_OFFSET(0.0f, -0.02f, -0.01f); + const glm::vec3 PIVOT_VECTOR_NORMALIZED = glm::normalize(PIVOT_OFFSET); + const glm::vec3 PIVOT_SINES = glm::max(glm::vec3(EPSILON, EPSILON, EPSILON), + glm::sqrt(glm::vec3(1.0f, 1.0f, 1.0f) - PIVOT_OFFSET * PIVOT_OFFSET)); + const glm::mat3 ACCELERATION_MATRIX( + 0.0f, PIVOT_OFFSET.z / PIVOT_SINES.x, -PIVOT_OFFSET.y / PIVOT_SINES.x, + -PIVOT_OFFSET.z / PIVOT_SINES.y, 0.0f, PIVOT_OFFSET.x / PIVOT_SINES.y, + PIVOT_OFFSET.y / PIVOT_SINES.z, -PIVOT_OFFSET.x / PIVOT_SINES.z, 0.0f); + // Update acceleration estimate - _estimatedAcceleration = _lastAcceleration - glm::inverse(estimatedRotation) * _gravity; - - static float ratioEstimate = 0.0f; - float angularAccelerationLength = glm::length(angularAcceleration); - float linearAccelerationLength = glm::length(estimatedAcceleration); - if (angularAccelerationLength > EPSILON && linearAccelerationLength > EPSILON) { - float ratio = linearAccelerationLength / angularAccelerationLength; - static float ratioEstimate = ratio; - ratioEstimate = ratioEstimate * 0.999 + ratio * 0.001; - printLog("%g %g\n", ratio, ratioEstimate); - } + _estimatedAcceleration = _lastAcceleration - glm::inverse(estimatedRotation) * _gravity - + ACCELERATION_MATRIX * angularAcceleration; // Update estimated position and velocity float const DECAY_VELOCITY = 0.95f; From a34f9a0ef3142091f5d053eccdc41052111cc91a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Jun 2013 18:41:49 -0700 Subject: [PATCH 21/71] Need to include SharedUtil. --- interface/src/SerialInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 407f06f736..2e5124c1b3 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -6,6 +6,7 @@ // #include "SerialInterface.h" +#include "SharedUtil.h" #include "Util.h" #include #include From 988c4f97b04e13804eba41c03e3e6a8c3c6640e9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 10 Jun 2013 18:43:11 -0700 Subject: [PATCH 22/71] This should be the normalized offset. --- interface/src/SerialInterface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 2e5124c1b3..7c4d1ac86f 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -241,9 +241,9 @@ void SerialInterface::readData(float deltaTime) { // The acceleration matrix transforms angular to linear accelerations const glm::vec3 PIVOT_OFFSET(0.0f, -0.02f, -0.01f); - const glm::vec3 PIVOT_VECTOR_NORMALIZED = glm::normalize(PIVOT_OFFSET); + const glm::vec3 PIVOT_OFFSET_NORMALIZED = glm::normalize(PIVOT_OFFSET); const glm::vec3 PIVOT_SINES = glm::max(glm::vec3(EPSILON, EPSILON, EPSILON), - glm::sqrt(glm::vec3(1.0f, 1.0f, 1.0f) - PIVOT_OFFSET * PIVOT_OFFSET)); + glm::sqrt(glm::vec3(1.0f, 1.0f, 1.0f) - PIVOT_OFFSET_NORMALIZED * PIVOT_OFFSET_NORMALIZED)); const glm::mat3 ACCELERATION_MATRIX( 0.0f, PIVOT_OFFSET.z / PIVOT_SINES.x, -PIVOT_OFFSET.y / PIVOT_SINES.x, -PIVOT_OFFSET.z / PIVOT_SINES.y, 0.0f, PIVOT_OFFSET.x / PIVOT_SINES.y, From 73ceea7795dbe8db4f58d4fb0af058e9d43927a8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 10:55:28 -0700 Subject: [PATCH 23/71] Working on "learning" the acceleration matrices. --- interface/src/SerialInterface.cpp | 55 ++++++++++++++++++++++++------- interface/src/SerialInterface.h | 7 +++- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 7c4d1ac86f..cbd03f801b 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -239,19 +239,50 @@ void SerialInterface::readData(float deltaTime) { glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) * glm::quat(glm::radians(deltaTime * _lastRotationRates)); - // The acceleration matrix transforms angular to linear accelerations - const glm::vec3 PIVOT_OFFSET(0.0f, -0.02f, -0.01f); - const glm::vec3 PIVOT_OFFSET_NORMALIZED = glm::normalize(PIVOT_OFFSET); - const glm::vec3 PIVOT_SINES = glm::max(glm::vec3(EPSILON, EPSILON, EPSILON), - glm::sqrt(glm::vec3(1.0f, 1.0f, 1.0f) - PIVOT_OFFSET_NORMALIZED * PIVOT_OFFSET_NORMALIZED)); - const glm::mat3 ACCELERATION_MATRIX( - 0.0f, PIVOT_OFFSET.z / PIVOT_SINES.x, -PIVOT_OFFSET.y / PIVOT_SINES.x, - -PIVOT_OFFSET.z / PIVOT_SINES.y, 0.0f, PIVOT_OFFSET.x / PIVOT_SINES.y, - PIVOT_OFFSET.y / PIVOT_SINES.z, -PIVOT_OFFSET.x / PIVOT_SINES.z, 0.0f); + // Update acceleration estimate: first, subtract gravity as rotated into current frame + _estimatedAcceleration = _lastAcceleration - glm::inverse(estimatedRotation) * _gravity; + + // Consider updating our angular velocity/acceleration to linear acceleration mapping + if (glm::length(_lastRotationRates) > EPSILON || glm::length(angularAcceleration) > EPSILON) { + // compute predicted linear acceleration, find error between actual and predicted + glm::vec3 predictedAcceleration = _angularVelocityToLinearAccel * _lastRotationRates + + _angularAccelToLinearAccel * angularAcceleration; + glm::vec3 error = _estimatedAcceleration - predictedAcceleration; - // Update acceleration estimate - _estimatedAcceleration = _lastAcceleration - glm::inverse(estimatedRotation) * _gravity - - ACCELERATION_MATRIX * angularAcceleration; + // adjust according to error in each dimension, in proportion to input magnitudes + for (int i = 0; i < 3; i++) { + if (fabsf(error[i]) < EPSILON) { + continue; + } + const float LEARNING_RATE = 0.1f; + float rateSum = fabsf(_lastRotationRates.x) + fabsf(_lastRotationRates.y) + fabsf(_lastRotationRates.z); + if (rateSum > EPSILON) { + for (int j = 0; j < 3; j++) { + float proportion = LEARNING_RATE * fabsf(_lastRotationRates[j]) / rateSum; + if (proportion > EPSILON) { + _angularVelocityToLinearAccel[j][i] += error[i] * proportion / _lastRotationRates[j]; + } + } + } + float accelSum = fabsf(angularAcceleration.x) + fabsf(angularAcceleration.y) + fabsf(angularAcceleration.z); + if (accelSum > EPSILON) { + for (int j = 0; j < 3; j++) { + float proportion = LEARNING_RATE * fabsf(angularAcceleration[j]) / accelSum; + if (proportion > EPSILON) { + _angularAccelToLinearAccel[j][i] += error[i] * proportion / angularAcceleration[j]; + } + } + } + } + } + + printLog("%g %g %g\n", _angularVelocityToLinearAccel[0][0], _angularVelocityToLinearAccel[1][0], _angularVelocityToLinearAccel[2][0]); + printLog("%g %g %g\n", _angularVelocityToLinearAccel[0][1], _angularVelocityToLinearAccel[1][1], _angularVelocityToLinearAccel[2][1]); + printLog("%g %g %g\n\n", _angularVelocityToLinearAccel[0][2], _angularVelocityToLinearAccel[1][2], _angularVelocityToLinearAccel[2][2]); + + printLog("%g %g %g\n", _angularAccelToLinearAccel[0][0], _angularAccelToLinearAccel[1][0], _angularAccelToLinearAccel[2][0]); + printLog("%g %g %g\n", _angularAccelToLinearAccel[0][1], _angularAccelToLinearAccel[1][1], _angularAccelToLinearAccel[2][1]); + printLog("%g %g %g\n\n", _angularAccelToLinearAccel[0][2], _angularAccelToLinearAccel[1][2], _angularAccelToLinearAccel[2][2]); // Update estimated position and velocity float const DECAY_VELOCITY = 0.95f; diff --git a/interface/src/SerialInterface.h b/interface/src/SerialInterface.h index a49c09c599..b7ead8c9d7 100644 --- a/interface/src/SerialInterface.h +++ b/interface/src/SerialInterface.h @@ -30,7 +30,9 @@ public: _estimatedPosition(0, 0, 0), _estimatedVelocity(0, 0, 0), _lastAcceleration(0, 0, 0), - _lastRotationRates(0, 0, 0) + _lastRotationRates(0, 0, 0), + _angularVelocityToLinearAccel(0), + _angularAccelToLinearAccel(0) {} void pair(); @@ -64,6 +66,9 @@ private: glm::vec3 _estimatedAcceleration; glm::vec3 _lastAcceleration; glm::vec3 _lastRotationRates; + + glm::mat3 _angularVelocityToLinearAccel; + glm::mat3 _angularAccelToLinearAccel; }; #endif From b1e3a0984b85d897b61b1a00b67c0413ead3777f Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 11 Jun 2013 11:10:09 -0700 Subject: [PATCH 24/71] Improved mouse look behavior to be smoother, removed transmitter debug. --- interface/src/Application.cpp | 2 +- interface/src/Avatar.cpp | 23 ++++++++--------------- interface/src/Transmitter.cpp | 4 +--- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eb03e1f592..0d73702a86 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1206,7 +1206,7 @@ void Application::initMenu() { (_gyroLook = optionsMenu->addAction("Gyro Look"))->setCheckable(true); _gyroLook->setChecked(false); (_mouseLook = optionsMenu->addAction("Mouse Look"))->setCheckable(true); - _mouseLook->setChecked(false); + _mouseLook->setChecked(true); (_showHeadMouse = optionsMenu->addAction("Head Mouse"))->setCheckable(true); _showHeadMouse->setChecked(false); (_transmitterDrives = optionsMenu->addAction("Transmitter Drive"))->setCheckable(true); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index e5c5a76a70..771d2cd891 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -317,30 +317,23 @@ glm::quat Avatar::getWorldAlignedOrientation () const { void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) { // Update head yaw and pitch based on mouse input - const float MOUSE_MOVE_RADIUS = 0.3f; - const float MOUSE_ROTATE_SPEED = 4.0f; - const float MOUSE_PITCH_SPEED = 2.0f; + const float MOUSE_ROTATE_SPEED = 0.01f; + const float MOUSE_PITCH_SPEED = 0.02f; const int TITLE_BAR_HEIGHT = 46; - float mouseLocationX = (float)mouseX / (float)screenWidth - 0.5f; - float mouseLocationY = (float)mouseY / (float)screenHeight - 0.5f; if ((mouseX > 1) && (mouseX < screenWidth) && (mouseY > TITLE_BAR_HEIGHT) && (mouseY < screenHeight)) { // // Mouse must be inside screen (not at edge) and not on title bar for movement to happen // - if (mouseLocationX > MOUSE_MOVE_RADIUS) { - _head.addYaw(-(mouseLocationX - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED); - } else if (mouseLocationX < -MOUSE_MOVE_RADIUS) { - _head.addYaw(-(mouseLocationX + MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED); - } - if (mouseLocationY > MOUSE_MOVE_RADIUS) { - _head.addPitch(-(mouseLocationY - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_PITCH_SPEED); - } else if (mouseLocationY < -MOUSE_MOVE_RADIUS) { - _head.addPitch(-(mouseLocationY + MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_PITCH_SPEED); + int pixelMoveThreshold = screenWidth / 6; + glm::vec2 mouseVector(mouseX - (screenWidth / 2), mouseY - (screenHeight / 2)); + if (glm::length(mouseVector) > pixelMoveThreshold) { + mouseVector -= glm::normalize(mouseVector) * (float) pixelMoveThreshold; + _head.addYaw(-mouseVector.x * MOUSE_ROTATE_SPEED); + _head.addPitch(-mouseVector.y * MOUSE_PITCH_SPEED); } } - return; } void Avatar::simulate(float deltaTime, Transmitter* transmitter) { diff --git a/interface/src/Transmitter.cpp b/interface/src/Transmitter.cpp index a02e864087..8cbb4a5c29 100644 --- a/interface/src/Transmitter.cpp +++ b/interface/src/Transmitter.cpp @@ -70,9 +70,7 @@ void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) { // Update estimated absolute position from rotation rates _estimatedRotation += _lastRotationRate * DELTA_TIME; - - printf("The accel %f, %f, %f\n", _lastAcceleration.x, _lastAcceleration.y, _lastAcceleration.z); - + // Sensor Fusion! Slowly adjust estimated rotation to be relative to gravity (average acceleration) const float GRAVITY_FOLLOW_RATE = 1.f; float rollAngle = angleBetween(glm::vec3(_lastAcceleration.x, _lastAcceleration.y, 0.f), glm::vec3(0,-1,0)) * From bf389de774a14b658850d3cf3940b83af787dd67 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 11:22:43 -0700 Subject: [PATCH 25/71] Testing a different coordinate conversion. --- interface/src/SerialInterface.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index cbd03f801b..03a03b87aa 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -216,8 +216,9 @@ void SerialInterface::readData(float deltaTime) { // From MPU-9150 register map, with setting on // highest resolution = +/- 2G - _lastAcceleration = glm::vec3(-accelXRate, -accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2; - + //_lastAcceleration = glm::vec3(-accelXRate, -accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2; + _lastAcceleration = glm::vec3(-accelYRate, accelXRate, accelZRate) * LSB_TO_METERS_PER_SECOND2; + int rollRate, yawRate, pitchRate; convertHexToInt(sensorBuffer + 22, rollRate); @@ -227,8 +228,12 @@ void SerialInterface::readData(float deltaTime) { // Convert the integer rates to floats const float LSB_TO_DEGREES_PER_SECOND = 1.f / 16.4f; // From MPU-9150 register map, 2000 deg/sec. glm::vec3 rotationRates; - rotationRates[0] = ((float) -pitchRate) * LSB_TO_DEGREES_PER_SECOND; - rotationRates[1] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND; + //rotationRates[0] = ((float) -pitchRate) * LSB_TO_DEGREES_PER_SECOND; + //rotationRates[1] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND; + //rotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND; + + rotationRates[0] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND; + rotationRates[1] = ((float) pitchRate) * LSB_TO_DEGREES_PER_SECOND; rotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND; // compute the angular acceleration From ff9e6f831c17bc0285f660681a8f296441a60853 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 11:31:01 -0700 Subject: [PATCH 26/71] Revert to previous coordinates. --- interface/src/SerialInterface.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 03a03b87aa..cbd03f801b 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -216,9 +216,8 @@ void SerialInterface::readData(float deltaTime) { // From MPU-9150 register map, with setting on // highest resolution = +/- 2G - //_lastAcceleration = glm::vec3(-accelXRate, -accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2; - _lastAcceleration = glm::vec3(-accelYRate, accelXRate, accelZRate) * LSB_TO_METERS_PER_SECOND2; - + _lastAcceleration = glm::vec3(-accelXRate, -accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2; + int rollRate, yawRate, pitchRate; convertHexToInt(sensorBuffer + 22, rollRate); @@ -228,12 +227,8 @@ void SerialInterface::readData(float deltaTime) { // Convert the integer rates to floats const float LSB_TO_DEGREES_PER_SECOND = 1.f / 16.4f; // From MPU-9150 register map, 2000 deg/sec. glm::vec3 rotationRates; - //rotationRates[0] = ((float) -pitchRate) * LSB_TO_DEGREES_PER_SECOND; - //rotationRates[1] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND; - //rotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND; - - rotationRates[0] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND; - rotationRates[1] = ((float) pitchRate) * LSB_TO_DEGREES_PER_SECOND; + rotationRates[0] = ((float) -pitchRate) * LSB_TO_DEGREES_PER_SECOND; + rotationRates[1] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND; rotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND; // compute the angular acceleration From 517bbe80a7d8a3efe86d2fe126efca0884cf1997 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 13:02:20 -0700 Subject: [PATCH 27/71] Initial values, report error. --- interface/src/SerialInterface.cpp | 2 ++ interface/src/SerialInterface.h | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index cbd03f801b..f4af4437d8 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -249,6 +249,8 @@ void SerialInterface::readData(float deltaTime) { _angularAccelToLinearAccel * angularAcceleration; glm::vec3 error = _estimatedAcceleration - predictedAcceleration; + printLog("error %g\n", glm::length(error)); + // adjust according to error in each dimension, in proportion to input magnitudes for (int i = 0; i < 3; i++) { if (fabsf(error[i]) < EPSILON) { diff --git a/interface/src/SerialInterface.h b/interface/src/SerialInterface.h index b7ead8c9d7..2bb7e541ac 100644 --- a/interface/src/SerialInterface.h +++ b/interface/src/SerialInterface.h @@ -31,8 +31,14 @@ public: _estimatedVelocity(0, 0, 0), _lastAcceleration(0, 0, 0), _lastRotationRates(0, 0, 0), - _angularVelocityToLinearAccel(0), - _angularAccelToLinearAccel(0) + _angularVelocityToLinearAccel( // experimentally derived initial values + 0.001f, -0.008f, 0.020f, + 0.003f, -0.003f, 0.025f, + 0.017f, 0.007f, 0.029f), + _angularAccelToLinearAccel( // experimentally derived initial values + 0.0f, 0.0f, 0.002f, + 0.0f, 0.0f, 0.002f, + -0.002f, -0.002f, 0.0f) {} void pair(); From 5ba1d3a28cbd980d813e0159e6f88d5485cdaf6b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 13:18:13 -0700 Subject: [PATCH 28/71] It ain't perfect, but I'm going with what I've got for now. --- interface/src/SerialInterface.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index f4af4437d8..af9c35196b 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -249,14 +249,15 @@ void SerialInterface::readData(float deltaTime) { _angularAccelToLinearAccel * angularAcceleration; glm::vec3 error = _estimatedAcceleration - predictedAcceleration; - printLog("error %g\n", glm::length(error)); + // the "error" is actually what we want: the linear acceleration minus rotational influences + _estimatedAcceleration = error; // adjust according to error in each dimension, in proportion to input magnitudes for (int i = 0; i < 3; i++) { if (fabsf(error[i]) < EPSILON) { continue; } - const float LEARNING_RATE = 0.1f; + const float LEARNING_RATE = 0.01f; float rateSum = fabsf(_lastRotationRates.x) + fabsf(_lastRotationRates.y) + fabsf(_lastRotationRates.z); if (rateSum > EPSILON) { for (int j = 0; j < 3; j++) { @@ -278,13 +279,8 @@ void SerialInterface::readData(float deltaTime) { } } - printLog("%g %g %g\n", _angularVelocityToLinearAccel[0][0], _angularVelocityToLinearAccel[1][0], _angularVelocityToLinearAccel[2][0]); - printLog("%g %g %g\n", _angularVelocityToLinearAccel[0][1], _angularVelocityToLinearAccel[1][1], _angularVelocityToLinearAccel[2][1]); - printLog("%g %g %g\n\n", _angularVelocityToLinearAccel[0][2], _angularVelocityToLinearAccel[1][2], _angularVelocityToLinearAccel[2][2]); - - printLog("%g %g %g\n", _angularAccelToLinearAccel[0][0], _angularAccelToLinearAccel[1][0], _angularAccelToLinearAccel[2][0]); - printLog("%g %g %g\n", _angularAccelToLinearAccel[0][1], _angularAccelToLinearAccel[1][1], _angularAccelToLinearAccel[2][1]); - printLog("%g %g %g\n\n", _angularAccelToLinearAccel[0][2], _angularAccelToLinearAccel[1][2], _angularAccelToLinearAccel[2][2]); + // rotate estimated acceleration into global rotation frame + _estimatedAcceleration = estimatedRotation * _estimatedAcceleration; // Update estimated position and velocity float const DECAY_VELOCITY = 0.95f; From b88380db6f01841aceded1cdaaf20758a6063fe1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 13:43:29 -0700 Subject: [PATCH 29/71] New values, slower learning. --- interface/src/SerialInterface.cpp | 2 +- interface/src/SerialInterface.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index af9c35196b..be1e6328da 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -257,7 +257,7 @@ void SerialInterface::readData(float deltaTime) { if (fabsf(error[i]) < EPSILON) { continue; } - const float LEARNING_RATE = 0.01f; + const float LEARNING_RATE = 0.001f; float rateSum = fabsf(_lastRotationRates.x) + fabsf(_lastRotationRates.y) + fabsf(_lastRotationRates.z); if (rateSum > EPSILON) { for (int j = 0; j < 3; j++) { diff --git a/interface/src/SerialInterface.h b/interface/src/SerialInterface.h index 2bb7e541ac..b10fba84ce 100644 --- a/interface/src/SerialInterface.h +++ b/interface/src/SerialInterface.h @@ -32,12 +32,12 @@ public: _lastAcceleration(0, 0, 0), _lastRotationRates(0, 0, 0), _angularVelocityToLinearAccel( // experimentally derived initial values - 0.001f, -0.008f, 0.020f, - 0.003f, -0.003f, 0.025f, - 0.017f, 0.007f, 0.029f), + 0.003f, -0.001f, -0.006f, + -0.005f, -0.001f, -0.006f, + 0.010f, 0.004f, 0.007f), _angularAccelToLinearAccel( // experimentally derived initial values 0.0f, 0.0f, 0.002f, - 0.0f, 0.0f, 0.002f, + 0.0f, 0.0f, 0.001f, -0.002f, -0.002f, 0.0f) {} From 47bd3bcdd7cc7bb971441a24e353b08c3b30adb7 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 14:03:49 -0700 Subject: [PATCH 30/71] Don't estimate acceleration before we know the gravity and don't update our matrices without acceleration. --- interface/src/SerialInterface.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index be1e6328da..2132f5a2de 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -240,10 +240,12 @@ void SerialInterface::readData(float deltaTime) { glm::quat(glm::radians(deltaTime * _lastRotationRates)); // Update acceleration estimate: first, subtract gravity as rotated into current frame - _estimatedAcceleration = _lastAcceleration - glm::inverse(estimatedRotation) * _gravity; + _estimatedAcceleration = (totalSamples < GRAVITY_SAMPLES) ? glm::vec3() : + _lastAcceleration - glm::inverse(estimatedRotation) * _gravity; // Consider updating our angular velocity/acceleration to linear acceleration mapping - if (glm::length(_lastRotationRates) > EPSILON || glm::length(angularAcceleration) > EPSILON) { + if (glm::length(_estimatedAcceleration) > EPSILON && + glm::length(_lastRotationRates) > EPSILON || glm::length(angularAcceleration) > EPSILON) { // compute predicted linear acceleration, find error between actual and predicted glm::vec3 predictedAcceleration = _angularVelocityToLinearAccel * _lastRotationRates + _angularAccelToLinearAccel * angularAcceleration; @@ -338,6 +340,7 @@ void SerialInterface::resetAverages() { _estimatedRotation = glm::vec3(0, 0, 0); _estimatedPosition = glm::vec3(0, 0, 0); _estimatedVelocity = glm::vec3(0, 0, 0); + _estimatedAcceleration = glm::vec3(0, 0, 0); } void SerialInterface::resetSerial() { From 4b890e2ccc677ce05c695ba3ad6c976012d37892 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 14:23:47 -0700 Subject: [PATCH 31/71] Let's see what the long-term average acceleration is. --- interface/src/SerialInterface.cpp | 7 ++++++- interface/src/SerialInterface.h | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 2132f5a2de..8e3cddf9bb 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -218,6 +218,11 @@ void SerialInterface::readData(float deltaTime) { _lastAcceleration = glm::vec3(-accelXRate, -accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2; + _averageAcceleration = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageAcceleration + + 1.f/(float)LONG_TERM_RATE_SAMPLES * _lastAcceleration; + + printLog("%g %g %g\n", _averageAcceleration.x, _averageAcceleration.y, _averageAcceleration.z); + int rollRate, yawRate, pitchRate; convertHexToInt(sensorBuffer + 22, rollRate); @@ -245,7 +250,7 @@ void SerialInterface::readData(float deltaTime) { // Consider updating our angular velocity/acceleration to linear acceleration mapping if (glm::length(_estimatedAcceleration) > EPSILON && - glm::length(_lastRotationRates) > EPSILON || glm::length(angularAcceleration) > EPSILON) { + (glm::length(_lastRotationRates) > EPSILON || glm::length(angularAcceleration) > EPSILON)) { // compute predicted linear acceleration, find error between actual and predicted glm::vec3 predictedAcceleration = _angularVelocityToLinearAccel * _lastRotationRates + _angularAccelToLinearAccel * angularAcceleration; diff --git a/interface/src/SerialInterface.h b/interface/src/SerialInterface.h index b10fba84ce..73f67fc618 100644 --- a/interface/src/SerialInterface.h +++ b/interface/src/SerialInterface.h @@ -73,6 +73,8 @@ private: glm::vec3 _lastAcceleration; glm::vec3 _lastRotationRates; + glm::vec3 _averageAcceleration; + glm::mat3 _angularVelocityToLinearAccel; glm::mat3 _angularAccelToLinearAccel; }; From d913f8dec03e419694108416add1f3902f6666de Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 14:25:05 -0700 Subject: [PATCH 32/71] Actually, we want it sans gravity. --- interface/src/SerialInterface.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 8e3cddf9bb..9933ba1129 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -218,10 +218,6 @@ void SerialInterface::readData(float deltaTime) { _lastAcceleration = glm::vec3(-accelXRate, -accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2; - _averageAcceleration = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageAcceleration + - 1.f/(float)LONG_TERM_RATE_SAMPLES * _lastAcceleration; - - printLog("%g %g %g\n", _averageAcceleration.x, _averageAcceleration.y, _averageAcceleration.z); int rollRate, yawRate, pitchRate; @@ -248,6 +244,11 @@ void SerialInterface::readData(float deltaTime) { _estimatedAcceleration = (totalSamples < GRAVITY_SAMPLES) ? glm::vec3() : _lastAcceleration - glm::inverse(estimatedRotation) * _gravity; + _averageAcceleration = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageAcceleration + + 1.f/(float)LONG_TERM_RATE_SAMPLES * _estimatedAcceleration; + + printLog("%g %g %g\n", _averageAcceleration.x, _averageAcceleration.y, _averageAcceleration.z); + // Consider updating our angular velocity/acceleration to linear acceleration mapping if (glm::length(_estimatedAcceleration) > EPSILON && (glm::length(_lastRotationRates) > EPSILON || glm::length(angularAcceleration) > EPSILON)) { From e77aee39676d2ffce770e402ed0356be1a5f6896 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 15:47:05 -0700 Subject: [PATCH 33/71] Show the average rotation rates, too. --- interface/src/SerialInterface.cpp | 7 ++++++- interface/src/SerialInterface.h | 1 + libraries/shared/src/SharedUtil.cpp | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 9933ba1129..02c672ba8f 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -236,6 +236,11 @@ void SerialInterface::readData(float deltaTime) { glm::vec3 angularAcceleration = (deltaTime < EPSILON) ? glm::vec3() : (rotationRates - _lastRotationRates) / deltaTime; _lastRotationRates = rotationRates; + _averageRotationRates = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageRotationRates + + 1.f/(float)LONG_TERM_RATE_SAMPLES * _lastRotationRates; + + printLog("r: %g %g %g\n", _averageRotationRates.x, _averageRotationRates.y, _averageRotationRates.z); + // Update raw rotation estimates glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) * glm::quat(glm::radians(deltaTime * _lastRotationRates)); @@ -247,7 +252,7 @@ void SerialInterface::readData(float deltaTime) { _averageAcceleration = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageAcceleration + 1.f/(float)LONG_TERM_RATE_SAMPLES * _estimatedAcceleration; - printLog("%g %g %g\n", _averageAcceleration.x, _averageAcceleration.y, _averageAcceleration.z); + printLog("a: %g %g %g\n", _averageAcceleration.x, _averageAcceleration.y, _averageAcceleration.z); // Consider updating our angular velocity/acceleration to linear acceleration mapping if (glm::length(_estimatedAcceleration) > EPSILON && diff --git a/interface/src/SerialInterface.h b/interface/src/SerialInterface.h index 73f67fc618..88af60ccbe 100644 --- a/interface/src/SerialInterface.h +++ b/interface/src/SerialInterface.h @@ -74,6 +74,7 @@ private: glm::vec3 _lastRotationRates; glm::vec3 _averageAcceleration; + glm::vec3 _averageRotationRates; glm::mat3 _angularVelocityToLinearAccel; glm::mat3 _angularAccelToLinearAccel; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 30aa75b461..697719b36d 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -102,12 +102,12 @@ void setAtBit(unsigned char& byte, int bitIndex) { } int getSemiNibbleAt(unsigned char& byte, int bitIndex) { - return (byte >> (7 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11 + return (byte >> (6 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11 } void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { //assert(value <= 3 && value >= 0); - byte += ((value & 3) << (7 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 + byte += ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 } From 090df81afebb29d8c95a2141cab728f9476f3d22 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 15:58:50 -0700 Subject: [PATCH 34/71] Fixes to align better with previous code. --- interface/src/SerialInterface.cpp | 16 +++++++++------- interface/src/SerialInterface.h | 7 ++++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 02c672ba8f..86755e28b5 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -232,15 +232,15 @@ void SerialInterface::readData(float deltaTime) { rotationRates[1] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND; rotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND; + // update and subtract the long term average + _averageRotationRates = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageRotationRates + + 1.f/(float)LONG_TERM_RATE_SAMPLES * rotationRates; + rotationRates -= _averageRotationRates; + // compute the angular acceleration glm::vec3 angularAcceleration = (deltaTime < EPSILON) ? glm::vec3() : (rotationRates - _lastRotationRates) / deltaTime; _lastRotationRates = rotationRates; - - _averageRotationRates = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageRotationRates + - 1.f/(float)LONG_TERM_RATE_SAMPLES * _lastRotationRates; - printLog("r: %g %g %g\n", _averageRotationRates.x, _averageRotationRates.y, _averageRotationRates.z); - // Update raw rotation estimates glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) * glm::quat(glm::radians(deltaTime * _lastRotationRates)); @@ -249,10 +249,10 @@ void SerialInterface::readData(float deltaTime) { _estimatedAcceleration = (totalSamples < GRAVITY_SAMPLES) ? glm::vec3() : _lastAcceleration - glm::inverse(estimatedRotation) * _gravity; + // update and subtract the long term average _averageAcceleration = (1.f - 1.f/(float)LONG_TERM_RATE_SAMPLES) * _averageAcceleration + 1.f/(float)LONG_TERM_RATE_SAMPLES * _estimatedAcceleration; - - printLog("a: %g %g %g\n", _averageAcceleration.x, _averageAcceleration.y, _averageAcceleration.z); + _estimatedAcceleration -= _averageAcceleration; // Consider updating our angular velocity/acceleration to linear acceleration mapping if (glm::length(_estimatedAcceleration) > EPSILON && @@ -347,6 +347,8 @@ void SerialInterface::readData(float deltaTime) { void SerialInterface::resetAverages() { totalSamples = 0; _gravity = glm::vec3(0, 0, 0); + _averageRotationRates = glm::vec3(0, 0, 0); + _averageAcceleration = glm::vec3(0, 0, 0); _lastRotationRates = glm::vec3(0, 0, 0); _estimatedRotation = glm::vec3(0, 0, 0); _estimatedPosition = glm::vec3(0, 0, 0); diff --git a/interface/src/SerialInterface.h b/interface/src/SerialInterface.h index 88af60ccbe..8c918e65ff 100644 --- a/interface/src/SerialInterface.h +++ b/interface/src/SerialInterface.h @@ -26,6 +26,8 @@ class SerialInterface { public: SerialInterface() : active(false), _gravity(0, 0, 0), + _averageRotationRates(0, 0, 0), + _averageAcceleration(0, 0, 0), _estimatedRotation(0, 0, 0), _estimatedPosition(0, 0, 0), _estimatedVelocity(0, 0, 0), @@ -66,6 +68,8 @@ private: int totalSamples; timeval lastGoodRead; glm::vec3 _gravity; + glm::vec3 _averageRotationRates; + glm::vec3 _averageAcceleration; glm::vec3 _estimatedRotation; glm::vec3 _estimatedPosition; glm::vec3 _estimatedVelocity; @@ -73,9 +77,6 @@ private: glm::vec3 _lastAcceleration; glm::vec3 _lastRotationRates; - glm::vec3 _averageAcceleration; - glm::vec3 _averageRotationRates; - glm::mat3 _angularVelocityToLinearAccel; glm::mat3 _angularAccelToLinearAccel; }; From ee526265a1c3b8fd40895651785968319dc9f1d3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 16:00:14 -0700 Subject: [PATCH 35/71] Fix for nibble packing. --- libraries/shared/src/SharedUtil.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 30aa75b461..697719b36d 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -102,12 +102,12 @@ void setAtBit(unsigned char& byte, int bitIndex) { } int getSemiNibbleAt(unsigned char& byte, int bitIndex) { - return (byte >> (7 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11 + return (byte >> (6 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11 } void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { //assert(value <= 3 && value >= 0); - byte += ((value & 3) << (7 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 + byte += ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 } From 35e18abcbd7e6d1d04547001657d2bf33c85d8c6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 16:27:39 -0700 Subject: [PATCH 36/71] Let's try using estimated velocity to control "lean." --- interface/src/Avatar.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 32b35aebac..9a59e2b804 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -285,18 +285,8 @@ void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterfa _head.setRoll(estimatedRotation.z * AMPLIFY_ROLL); // Update head lean distance based on accelerometer data - glm::vec3 headRotationRates(_head.getPitch(), _head.getYaw(), _head.getRoll()); - - glm::vec3 leaning = (serialInterface->getLastAcceleration() - serialInterface->getGravity()) - * LEAN_SENSITIVITY - * (1.f - fminf(glm::length(headRotationRates), HEAD_RATE_MAX) / HEAD_RATE_MAX); - leaning.y = 0.f; - if (glm::length(leaning) < LEAN_MAX) { - _head.setLeanForward(_head.getLeanForward() * (1.f - LEAN_AVERAGING * deltaTime) + - (LEAN_AVERAGING * deltaTime) * leaning.z * LEAN_SENSITIVITY); - _head.setLeanSideways(_head.getLeanSideways() * (1.f - LEAN_AVERAGING * deltaTime) + - (LEAN_AVERAGING * deltaTime) * leaning.x * LEAN_SENSITIVITY); - } + _bodyPitchDelta = serialInterface->getEstimatedVelocity().z * LEAN_SENSITIVITY; + _bodyRollDelta = -serialInterface->getEstimatedVelocity().x * LEAN_SENSITIVITY; } float Avatar::getAbsoluteHeadYaw() const { From c1c2439d2ca9f91d83e69556e71c21ed8f6d7d51 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 16:44:21 -0700 Subject: [PATCH 37/71] Let's try changing the torso rotation based on the gyros! --- interface/src/Avatar.cpp | 10 +++++----- interface/src/Skeleton.cpp | 6 +++--- interface/src/Skeleton.h | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 9a59e2b804..43056244ff 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -280,13 +280,13 @@ void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterfa const float AMPLIFY_ROLL = 2.f; glm::vec3 estimatedRotation = serialInterface->getEstimatedRotation(); - _head.setPitch(estimatedRotation.x * AMPLIFY_PITCH); - _head.setYaw(estimatedRotation.y * AMPLIFY_YAW); - _head.setRoll(estimatedRotation.z * AMPLIFY_ROLL); + //_head.setPitch(estimatedRotation.x * AMPLIFY_PITCH); + //_head.setYaw(estimatedRotation.y * AMPLIFY_YAW); + //_head.setRoll(estimatedRotation.z * AMPLIFY_ROLL); // Update head lean distance based on accelerometer data - _bodyPitchDelta = serialInterface->getEstimatedVelocity().z * LEAN_SENSITIVITY; - _bodyRollDelta = -serialInterface->getEstimatedVelocity().x * LEAN_SENSITIVITY; + glm::vec3 estimatedPosition = serialInterface->getEstimatedPosition(); + _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(estimatedRotation)); } float Avatar::getAbsoluteHeadYaw() const { diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 2fa43c9010..fcec90b542 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -132,15 +132,15 @@ void Skeleton::update(float deltaTime, const glm::quat& orientation, glm::vec3 p for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { if (joint[b].parent == AVATAR_JOINT_NULL) { - joint[b].rotation = orientation; + joint[b].absoluteRotation = orientation * joint[b].rotation; joint[b].position = position; } else { - joint[b].rotation = joint[ joint[b].parent ].rotation; + joint[b].absoluteRotation = joint[ joint[b].parent ].absoluteRotation * joint[b].rotation; joint[b].position = joint[ joint[b].parent ].position; } - glm::vec3 rotatedJointVector = joint[b].rotation * joint[b].defaultPosePosition; + glm::vec3 rotatedJointVector = joint[b].absoluteRotation * joint[b].defaultPosePosition; joint[b].position += rotatedJointVector; } } diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index e98c2e7b12..ec40f18cb3 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -68,6 +68,7 @@ public: glm::quat absoluteBindPoseRotation; // the absolute rotation when the avatar is in the "T-pose" float bindRadius; // the radius of the bone capsule that envelops the vertices to bind glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion + glm::quat absoluteRotation; // the absolute rotation of the joint as a quaternion float length; // the length of vector connecting the joint and its parent }; From 70c5a941d7d9118aab8b86e5450aaeaf6d133d39 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 17:01:06 -0700 Subject: [PATCH 38/71] Now let's try using the estimated position to calculate lean. --- interface/src/Avatar.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 43056244ff..5547fe5e43 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -280,13 +280,18 @@ void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterfa const float AMPLIFY_ROLL = 2.f; glm::vec3 estimatedRotation = serialInterface->getEstimatedRotation(); - //_head.setPitch(estimatedRotation.x * AMPLIFY_PITCH); - //_head.setYaw(estimatedRotation.y * AMPLIFY_YAW); - //_head.setRoll(estimatedRotation.z * AMPLIFY_ROLL); + _head.setPitch(estimatedRotation.x * AMPLIFY_PITCH); + _head.setYaw(estimatedRotation.y * AMPLIFY_YAW); + _head.setRoll(estimatedRotation.z * AMPLIFY_ROLL); - // Update head lean distance based on accelerometer data + // Update torso lean distance based on accelerometer data glm::vec3 estimatedPosition = serialInterface->getEstimatedPosition(); - _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(estimatedRotation)); + const float TORSO_LENGTH = 0.5f; + const float MAX_LEAN_RADIANS = PIf / 4; + _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::vec3( + glm::clamp(atanf(estimatedPosition.z / TORSO_LENGTH), -MAX_LEAN_RADIANS, MAX_LEAN_RADIANS), + 0.0f, + glm::clamp(atanf(-estimatedPosition.x / TORSO_LENGTH), -MAX_LEAN_RADIANS, MAX_LEAN_RADIANS))); } float Avatar::getAbsoluteHeadYaw() const { From 648aacb53d8f6ce0075b44c64b45aa2a5bedbdcf Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 17:26:41 -0700 Subject: [PATCH 39/71] Let's use a fixed vector for the camera position so that the target doesn't move with lean. --- interface/src/Application.cpp | 6 +++--- interface/src/Avatar.cpp | 6 ++++++ interface/src/Avatar.h | 3 +++ interface/src/SerialInterface.cpp | 4 ++-- interface/src/Skeleton.cpp | 7 +++++++ interface/src/Skeleton.h | 1 + 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 51c6e65cb9..489150c8a1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -308,7 +308,7 @@ void Application::paintGL() { if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness (100.0f); - _myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE)); + _myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition()); _myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f))); } else if (OculusManager::isConnected()) { @@ -320,11 +320,11 @@ void Application::paintGL() { } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTightness(0.0f); // In first person, camera follows head exactly without delay - _myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE)); + _myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(_headCameraPitchYawScale)); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - _myCamera.setTargetPosition(_myAvatar.getHeadJointPosition()); + _myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(_headCameraPitchYawScale)); } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 5547fe5e43..7d6e0aad37 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -103,9 +103,11 @@ Avatar::Avatar(Agent* owningAgent) : initializeBodyBalls(); _height = _skeleton.getHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius + _bodyBall[ BODY_BALL_HEAD_BASE ].radius; + _maxArmLength = _skeleton.getArmLength(); _pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; + _pelvisToHeadLength = _skeleton.getPelvisToHeadLength(); _avatarTouch.setReachableRadius(PERIPERSONAL_RADIUS); @@ -310,6 +312,10 @@ glm::quat Avatar::getWorldAlignedOrientation () const { return computeRotationFromBodyToWorldUp() * getOrientation(); } +glm::vec3 Avatar::getUprightHeadPosition() const { + return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, _pelvisToHeadLength, 0.0f); +} + void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) { // Update head yaw and pitch based on mouse input const float MOUSE_MOVE_RADIUS = 0.3f; diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 0fc5b31286..82d98a3a02 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -121,6 +121,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + glm::vec3 getUprightHeadPosition() const; + AvatarVoxelSystem* getVoxels() { return &_voxels; } // Set what driving keys are being pressed to control thrust levels @@ -185,6 +187,7 @@ private: int _driveKeys[MAX_DRIVE_KEYS]; float _pelvisStandingHeight; float _pelvisFloatingHeight; + float _pelvisToHeadLength; float _height; Balls* _balls; AvatarTouch _avatarTouch; diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 86755e28b5..76487bb668 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -296,8 +296,8 @@ void SerialInterface::readData(float deltaTime) { _estimatedAcceleration = estimatedRotation * _estimatedAcceleration; // Update estimated position and velocity - float const DECAY_VELOCITY = 0.95f; - float const DECAY_POSITION = 0.95f; + float const DECAY_VELOCITY = 0.975f; + float const DECAY_POSITION = 0.975f; _estimatedVelocity += deltaTime * _estimatedAcceleration; _estimatedPosition += deltaTime * _estimatedVelocity; _estimatedVelocity *= DECAY_VELOCITY; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index fcec90b542..1167194534 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -174,6 +174,13 @@ float Skeleton::getPelvisFloatingHeight() { FLOATING_HEIGHT; } +float Skeleton::getPelvisToHeadLength() { + return + joint[ AVATAR_JOINT_TORSO ].length + + joint[ AVATAR_JOINT_CHEST ].length + + joint[ AVATAR_JOINT_NECK_BASE ].length + + joint[ AVATAR_JOINT_HEAD_BASE ].length; +} diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index ec40f18cb3..bb953fe947 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -56,6 +56,7 @@ public: float getHeight(); float getPelvisStandingHeight(); float getPelvisFloatingHeight(); + float getPelvisToHeadLength(); //glm::vec3 getJointVectorFromParent(AvatarJointID jointID) {return joint[jointID].position - joint[joint[jointID].parent].position; } struct AvatarJoint From 82f03ffd8eba4d7413da0490d880cf93e412b63d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 17:53:49 -0700 Subject: [PATCH 40/71] Don't render the voxels when we're too close (i.e., in first person mode). --- interface/src/Avatar.cpp | 32 ++++++++++++++++---------------- interface/src/Avatar.h | 1 + 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 7d6e0aad37..1b219e440e 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -1131,32 +1131,29 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { return glm::angleAxis(angle * proportion, axis); } -void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { - +float Avatar::getBallRenderAlpha(int ball, bool lookingInMirror) const { const float RENDER_OPAQUE_BEYOND = 1.0f; // Meters beyond which body is shown opaque const float RENDER_TRANSLUCENT_BEYOND = 0.5f; + float distanceToCamera = glm::length(_cameraPosition - _bodyBall[ball].position); + return (lookingInMirror || _owningAgent) ? 1.0f : glm::clamp( + (distanceToCamera - RENDER_TRANSLUCENT_BEYOND) / (RENDER_OPAQUE_BEYOND - RENDER_TRANSLUCENT_BEYOND), 0.f, 1.f); +} + +void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { + + // Render the body as balls and cones if (renderAvatarBalls || !_voxels.getVoxelURL().isValid()) { for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { - float distanceToCamera = glm::length(_cameraPosition - _bodyBall[b].position); - - float alpha = lookingInMirror ? 1.0f : glm::clamp((distanceToCamera - RENDER_TRANSLUCENT_BEYOND) / - (RENDER_OPAQUE_BEYOND - RENDER_TRANSLUCENT_BEYOND), 0.f, 1.f); - - if (lookingInMirror || _owningAgent) { - alpha = 1.0f; - } + float alpha = getBallRenderAlpha(b, lookingInMirror); // Always render other people, and render myself when beyond threshold distance if (b == BODY_BALL_HEAD_BASE) { // the head is rendered as a special - if (lookingInMirror || _owningAgent || distanceToCamera > RENDER_OPAQUE_BEYOND * 0.5) { + if (alpha > 0.0f) { _head.render(lookingInMirror, _cameraPosition, alpha); } - } else if (_owningAgent || distanceToCamera > RENDER_TRANSLUCENT_BEYOND - || b == BODY_BALL_RIGHT_ELBOW - || b == BODY_BALL_RIGHT_WRIST - || b == BODY_BALL_RIGHT_FINGERTIPS ) { + } else if (alpha > 0.0f) { // Render the body ball sphere if (_owningAgent || b == BODY_BALL_RIGHT_ELBOW || b == BODY_BALL_RIGHT_WRIST @@ -1208,7 +1205,10 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { } } else { // Render the body's voxels - _voxels.render(false); + float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror); + if (alpha > 0.0f) { + _voxels.render(false); + } } } diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 82d98a3a02..de76092328 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -204,6 +204,7 @@ private: // private methods... glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; + float getBallRenderAlpha(int ball, bool lookingInMirror) const; void renderBody(bool lookingInMirror, bool renderAvatarBalls); void initializeBodyBalls(); void resetBodyBalls(); From 7ef2a2c5d98af51de1f001b396fb57b29c4680d9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 18:06:05 -0700 Subject: [PATCH 41/71] Set/get lean to/from network data. --- interface/src/Avatar.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 1b219e440e..e33624467e 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -289,11 +289,9 @@ void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterfa // Update torso lean distance based on accelerometer data glm::vec3 estimatedPosition = serialInterface->getEstimatedPosition(); const float TORSO_LENGTH = 0.5f; - const float MAX_LEAN_RADIANS = PIf / 4; - _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::vec3( - glm::clamp(atanf(estimatedPosition.z / TORSO_LENGTH), -MAX_LEAN_RADIANS, MAX_LEAN_RADIANS), - 0.0f, - glm::clamp(atanf(-estimatedPosition.x / TORSO_LENGTH), -MAX_LEAN_RADIANS, MAX_LEAN_RADIANS))); + const float MAX_LEAN = 45.0f; + _head.setLeanSideways(glm::clamp(glm::degrees(atanf(-estimatedPosition.x / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN)); + _head.setLeanForward(glm::clamp(glm::degrees(atanf(estimatedPosition.z / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN)); } float Avatar::getAbsoluteHeadYaw() const { @@ -355,6 +353,10 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { // update balls if (_balls) { _balls->simulate(deltaTime); } + // update torso rotation based on head lean + _skeleton.joint[AVATAR_JOINT_TORSO].rotation = glm::quat(glm::radians(glm::vec3( + _head.getLeanForward(), 0.0f, _head.getLeanSideways()))); + // update avatar skeleton _skeleton.update(deltaTime, getOrientation(), _position); From c58eb0d5841ebf0f0b7548b29ef3f51cfdc3d717 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 11 Jun 2013 18:11:42 -0700 Subject: [PATCH 42/71] Bump the maximum voxels up to 10000. --- interface/src/AvatarVoxelSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 8a7708587f..dc3b937da9 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -17,7 +17,7 @@ #include "renderer/ProgramObject.h" const float AVATAR_TREE_SCALE = 1.0f; -const int MAX_VOXELS_PER_AVATAR = 2000; +const int MAX_VOXELS_PER_AVATAR = 10000; const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : From ad58d0aa23963ed83fea4eb1d8960b1175b40eff Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 11 Jun 2013 21:19:58 -0700 Subject: [PATCH 43/71] Adding voxel thrust on grabbing/dragging to move avatar --- interface/src/Application.cpp | 59 +++++++++++++++++++++++++++++++++++ interface/src/Application.h | 10 ++++++ interface/src/Avatar.cpp | 7 +++-- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 67dd0f7a15..71769b6be2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -721,6 +721,9 @@ void Application::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton) { _mouseX = event->x(); _mouseY = event->y(); + _mouseDragStartedX = _mouseX; + _mouseDragStartedY = _mouseY; + _mouseVoxelDragging = _mouseVoxel; _mousePressed = true; maybeEditVoxelUnderCursor(); @@ -1003,6 +1006,12 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { } } +const glm::vec3 Application::getMouseVoxelWorldCoordinates(VoxelDetail _mouseVoxel) { + return glm::vec3((_mouseVoxel.x + _mouseVoxel.s / 2.f) * TREE_SCALE, + (_mouseVoxel.y + _mouseVoxel.s / 2.f) * TREE_SCALE, + (_mouseVoxel.z + _mouseVoxel.s / 2.f) * TREE_SCALE); +} + void Application::decreaseVoxelSize() { _mouseVoxelScale /= 2; } @@ -1432,6 +1441,26 @@ void Application::update(float deltaTime) { // tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); + // If we are dragging on a voxel, add thrust according to the amount the mouse is dragging + const float VOXEL_GRAB_THRUST = 10.0f; + if (_mousePressed && (_mouseVoxel.s != 0)) { + glm::vec2 mouseDrag(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY); + glm::quat orientation = _myAvatar.getOrientation(); + //glm::vec3 front = orientation * IDENTITY_FRONT; + //glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 towardVoxel = getMouseVoxelWorldCoordinates(_mouseVoxelDragging) + - _myAvatar.getCameraPosition(); + glm::vec3 lateralToVoxel = glm::cross(up, glm::normalize(towardVoxel)) * glm::length(towardVoxel); + _voxelThrust = glm::vec3(0, 0, 0); + _voxelThrust += towardVoxel * VOXEL_GRAB_THRUST * deltaTime * mouseDrag.y; + _voxelThrust += lateralToVoxel * VOXEL_GRAB_THRUST * deltaTime * mouseDrag.x; + + // Add thrust from voxel grabbing to the avatar + _myAvatar.addThrust(_voxelThrust); + + } + _mouseVoxel.s = 0.0f; if (checkedVoxelModeAction() != 0 && (fabs(_myAvatar.getVelocity().x) + @@ -1951,6 +1980,10 @@ void Application::displaySide(Camera& whichCamera) { glEnable(GL_LIGHTING); glEnable(GL_DEPTH_TEST); + // Enable to show line from me to the voxel I am touching + //renderLineToTouchedVoxel(); + renderThrustAtVoxel(_voxelThrust); + // draw a red sphere float sphereRadius = 0.25f; glColor3f(1,0,0); @@ -2167,6 +2200,32 @@ void Application::displayStats() { } } +void Application::renderThrustAtVoxel(glm::vec3 thrust) { + if (_mousePressed) { + glColor3f(1, 0, 0); + glLineWidth(2.0f); + glBegin(GL_LINES); + glm::vec3 voxelTouched = getMouseVoxelWorldCoordinates(_mouseVoxelDragging); + glVertex3f(voxelTouched.x, voxelTouched.y, voxelTouched.z); + glVertex3f(voxelTouched.x + thrust.x, voxelTouched.y + thrust.y, voxelTouched.z + thrust.z); + glEnd(); + } + +} +void Application::renderLineToTouchedVoxel() { + // Draw a teal line to the voxel I am currently dragging on + if (_mousePressed) { + glColor3f(0, 1, 1); + glLineWidth(2.0f); + glBegin(GL_LINES); + glm::vec3 voxelTouched = getMouseVoxelWorldCoordinates(_mouseVoxelDragging); + glVertex3f(voxelTouched.x, voxelTouched.y, voxelTouched.z); + glm::vec3 headPosition = _myAvatar.getHeadJointPosition(); + glVertex3fv(&headPosition.x); + glEnd(); + } +} + ///////////////////////////////////////////////////////////////////////////////////// // renderViewFrustum() // diff --git a/interface/src/Application.h b/interface/src/Application.h index 4f33f8fb1e..7660b8651f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -67,6 +67,8 @@ public: void wheelEvent(QWheelEvent* event); + const glm::vec3 getMouseVoxelWorldCoordinates(VoxelDetail _mouseVoxel); + Avatar* getAvatar() { return &_myAvatar; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } @@ -142,6 +144,9 @@ private: void renderViewFrustum(ViewFrustum& viewFrustum); + void renderLineToTouchedVoxel(); + void renderThrustAtVoxel(glm::vec3 thrust); + void setupPaintingVoxel(); void shiftPaintingColor(); void maybeEditVoxelUnderCursor(); @@ -256,7 +261,12 @@ private: int _mouseX; int _mouseY; + int _mouseDragStartedX; + int _mouseDragStartedY; + VoxelDetail _mouseVoxelDragging; + glm::vec3 _voxelThrust; bool _mousePressed; // true if mouse has been pressed (clear when finished) + VoxelDetail _mouseVoxel; // details of the voxel under the mouse cursor float _mouseVoxelScale; // the scale for adding/removing voxels diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index a9c8a368f8..f336da2d8c 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -412,9 +412,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { const float THRUST_MAG = 600.0f; if (!_owningAgent) { - - _thrust = glm::vec3(0.0f, 0.0f, 0.0f); - + // Add Thrusts from keyboard if (_driveKeys[FWD ]) {_thrust += THRUST_MAG * deltaTime * front;} if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG * deltaTime * front;} @@ -468,6 +466,9 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { // add thrust to velocity _velocity += _thrust * deltaTime; + // Zero thrust out now that we've added it to velocity in this frame + _thrust = glm::vec3(0, 0, 0); + // calculate speed _speed = glm::length(_velocity); From 59c8d9d26aa9d5591f552d418128f7e2cddf5edc Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 10:25:28 -0700 Subject: [PATCH 44/71] Function cleanup, fixed misspelling, tweaked transparency distances to accomodate lean. --- interface/src/Avatar.cpp | 21 ++++++++------------- interface/src/Avatar.h | 3 +-- interface/src/Head.cpp | 11 ++++++----- interface/src/Head.h | 6 +++--- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index e33624467e..168fa80016 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -74,7 +74,6 @@ Avatar::Avatar(Agent* owningAgent) : _bodyRollDelta(0.0f), _movedHandOffset(0.0f, 0.0f, 0.0f), _mode(AVATAR_MODE_STANDING), - _cameraPosition(0.0f, 0.0f, 0.0f), _handHoldingPosition(0.0f, 0.0f, 0.0f), _velocity(0.0f, 0.0f, 0.0f), _thrust(0.0f, 0.0f, 0.0f), @@ -584,7 +583,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { // set head lookat position if (!_owningAgent) { if (_interactingOther) { - _head.setLookAtPosition(_interactingOther->caclulateAverageEyePosition()); + _head.setLookAtPosition(_interactingOther->calculateAverageEyePosition()); } else { _head.setLookAtPosition(glm::vec3(0.0f, 0.0f, 0.0f)); // 0,0,0 represents NOT looking at anything } @@ -914,9 +913,7 @@ void Avatar::setGravity(glm::vec3 gravity) { } void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) { - - _cameraPosition = Application::getInstance()->getCamera()->getPosition(); - + if (!_owningAgent && usingBigSphereCollisionTest) { // show TEST big sphere glColor4f(0.5f, 0.6f, 0.8f, 0.7); @@ -935,7 +932,7 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) { // if this is my avatar, then render my interactions with the other avatar if (!_owningAgent) { - _avatarTouch.render(getCameraPosition()); + _avatarTouch.render(Application::getInstance()->getCamera()->getPosition()); } // Render the balls @@ -1134,17 +1131,15 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { } float Avatar::getBallRenderAlpha(int ball, bool lookingInMirror) const { - const float RENDER_OPAQUE_BEYOND = 1.0f; // Meters beyond which body is shown opaque - const float RENDER_TRANSLUCENT_BEYOND = 0.5f; - float distanceToCamera = glm::length(_cameraPosition - _bodyBall[ball].position); + const float RENDER_OPAQUE_OUTSIDE = 1.25f; // render opaque if greater than this distance + const float DO_NOT_RENDER_INSIDE = 0.75f; // do not render if less than this distance + float distanceToCamera = glm::length(Application::getInstance()->getCamera()->getPosition() - _bodyBall[ball].position); return (lookingInMirror || _owningAgent) ? 1.0f : glm::clamp( - (distanceToCamera - RENDER_TRANSLUCENT_BEYOND) / (RENDER_OPAQUE_BEYOND - RENDER_TRANSLUCENT_BEYOND), 0.f, 1.f); + (distanceToCamera - DO_NOT_RENDER_INSIDE) / (RENDER_OPAQUE_OUTSIDE - DO_NOT_RENDER_INSIDE), 0.f, 1.f); } void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { - - // Render the body as balls and cones if (renderAvatarBalls || !_voxels.getVoxelURL().isValid()) { for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { @@ -1153,7 +1148,7 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) { // Always render other people, and render myself when beyond threshold distance if (b == BODY_BALL_HEAD_BASE) { // the head is rendered as a special if (alpha > 0.0f) { - _head.render(lookingInMirror, _cameraPosition, alpha); + _head.render(lookingInMirror, alpha); } } else if (alpha > 0.0f) { // Render the body ball sphere diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index de76092328..8391c81e96 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -177,7 +177,6 @@ private: glm::vec3 _movedHandOffset; AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ]; AvatarMode _mode; - glm::vec3 _cameraPosition; glm::vec3 _handHoldingPosition; glm::vec3 _velocity; glm::vec3 _thrust; @@ -202,7 +201,7 @@ private: AvatarVoxelSystem _voxels; // private methods... - glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) + glm::vec3 calculateAverageEyePosition() { return _head.calculateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; float getBallRenderAlpha(int ball, bool lookingInMirror) const; void renderBody(bool lookingInMirror, bool renderAvatarBalls); diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index d58c29f84d..c7fac99d8b 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -5,6 +5,7 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include +#include "Application.h" #include "Avatar.h" #include "Head.h" #include "Util.h" @@ -161,7 +162,7 @@ void Head::determineIfLookingAtSomething() { if ( fabs(_lookAtPosition.x + _lookAtPosition.y + _lookAtPosition.z) == 0.0 ) { // a lookatPosition of 0,0,0 signifies NOT looking _lookingAtSomething = false; } else { - glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - caclulateAverageEyePosition()); + glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - calculateAverageEyePosition()); float dot = glm::dot(targetLookatAxis, getFrontDirection()); if (dot < MINIMUM_EYE_ROTATION_DOT) { // too far off from center for the eyes to rotate _lookingAtSomething = false; @@ -202,7 +203,7 @@ void Head::calculateGeometry() { } -void Head::render(bool lookingInMirror, glm::vec3 cameraPosition, float alpha) { +void Head::render(bool lookingInMirror, float alpha) { _renderAlpha = alpha; _lookingInMirror = lookingInMirror; @@ -212,7 +213,7 @@ void Head::render(bool lookingInMirror, glm::vec3 cameraPosition, float alpha) { glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); - renderMohawk(cameraPosition); + renderMohawk(); renderHeadSphere(); renderEyeBalls(); renderEars(); @@ -256,7 +257,7 @@ void Head::createMohawk() { } } -void Head::renderMohawk(glm::vec3 cameraPosition) { +void Head::renderMohawk() { if (!_mohawkTriangleFan) { createMohawk(); @@ -267,7 +268,7 @@ void Head::renderMohawk(glm::vec3 cameraPosition) { glm::vec3 baseAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition; glm::vec3 midAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition; - glm::vec3 viewVector = _hairTuft[t].basePosition - cameraPosition; + glm::vec3 viewVector = _hairTuft[t].basePosition - Application::getInstance()->getCamera()->getPosition(); glm::vec3 basePerpendicular = glm::normalize(glm::cross(baseAxis, viewVector)); glm::vec3 midPerpendicular = glm::normalize(glm::cross(midAxis, viewVector)); diff --git a/interface/src/Head.h b/interface/src/Head.h index 4150cbbc50..d331b98efc 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -33,8 +33,8 @@ public: void reset(); void simulate(float deltaTime, bool isMine); - void render(bool lookingInMirror, glm::vec3 cameraPosition, float alpha); - void renderMohawk(glm::vec3 cameraPosition); + void render(bool lookingInMirror, float alpha); + void renderMohawk(); void setScale (float scale ) { _scale = scale; } void setPosition (glm::vec3 position ) { _position = position; } @@ -55,7 +55,7 @@ public: const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) float getAverageLoudness() {return _averageLoudness;}; - glm::vec3 caclulateAverageEyePosition() { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; } + glm::vec3 calculateAverageEyePosition() { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; } float yawRate; float noise; From 3546bcc10167fc87fa39ed6e5a11e0aa65b723f5 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Jun 2013 11:36:28 -0700 Subject: [PATCH 45/71] Avatar can set velocity, velocity set to zero on reset --- interface/src/Application.cpp | 2 ++ interface/src/Avatar.h | 1 + 2 files changed, 3 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4c37be98c3..2de3b8295f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2502,6 +2502,8 @@ void Application::resetSensors() { QCursor::setPos(_headMouseX, _headMouseY); _myAvatar.reset(); _myTransmitter.resetLevels(); + _myAvatar.setVelocity(glm::vec3(0,0,0)); + _myAvatar.setThrust(glm::vec3(0,0,0)); } static void setShortcutsEnabled(QWidget* widget, bool enabled) { diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index de76092328..4018764ffc 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -96,6 +96,7 @@ public: void setMovedHandOffset (glm::vec3 movedHandOffset ) { _movedHandOffset = movedHandOffset;} void setThrust (glm::vec3 newThrust ) { _thrust = newThrust; }; void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors);} + void setVelocity (const glm::vec3 velocity ) { _velocity = velocity; }; void setGravity (glm::vec3 gravity); void setMouseRay (const glm::vec3 &origin, const glm::vec3 &direction); void setOrientation (const glm::quat& orientation); From 26ca1a9a1d4225b8295927cb6985d48936554eda Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Jun 2013 12:58:45 -0700 Subject: [PATCH 46/71] Remove shortcut on ground plane 'G', was conflicting with turning gravity on/off --- interface/src/Application.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2de3b8295f..445702aed3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1245,7 +1245,6 @@ void Application::initMenu() { _renderAtmosphereOn->setShortcut(Qt::SHIFT | Qt::Key_A); (_renderGroundPlaneOn = renderMenu->addAction("Ground Plane"))->setCheckable(true); _renderGroundPlaneOn->setChecked(true); - _renderGroundPlaneOn->setShortcut(Qt::SHIFT | Qt::Key_G); (_renderAvatarsOn = renderMenu->addAction("Avatars"))->setCheckable(true); _renderAvatarsOn->setChecked(true); (_renderAvatarBalls = renderMenu->addAction("Avatar as Balls"))->setCheckable(true); @@ -1446,11 +1445,12 @@ void Application::update(float deltaTime) { if (_mousePressed && (_mouseVoxel.s != 0)) { glm::vec2 mouseDrag(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY); glm::quat orientation = _myAvatar.getOrientation(); - //glm::vec3 front = orientation * IDENTITY_FRONT; - //glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; glm::vec3 up = orientation * IDENTITY_UP; glm::vec3 towardVoxel = getMouseVoxelWorldCoordinates(_mouseVoxelDragging) - _myAvatar.getCameraPosition(); + towardVoxel = front * glm::length(towardVoxel); glm::vec3 lateralToVoxel = glm::cross(up, glm::normalize(towardVoxel)) * glm::length(towardVoxel); _voxelThrust = glm::vec3(0, 0, 0); _voxelThrust += towardVoxel * VOXEL_GRAB_THRUST * deltaTime * mouseDrag.y; From 52c616b688dbef39886dec3745365b3969fedb63 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 13:06:28 -0700 Subject: [PATCH 47/71] Added configurable lean scale, fixed loadSetting. --- interface/src/Application.cpp | 5 +++++ interface/src/Avatar.cpp | 7 ++++++- interface/src/Avatar.h | 4 +++- interface/src/Util.cpp | 4 ++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 489150c8a1..e3c7ca0bdf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -880,6 +880,10 @@ void Application::editPreferences() { headCameraPitchYawScale->setValue(_headCameraPitchYawScale); form->addRow("Head Camera Pitch/Yaw Scale:", headCameraPitchYawScale); + QDoubleSpinBox* leanScale = new QDoubleSpinBox(); + leanScale->setValue(_myAvatar.getLeanScale()); + form->addRow("Lean Scale:", leanScale); + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); @@ -893,6 +897,7 @@ void Application::editPreferences() { sendAvatarVoxelURLMessage(url); _headCameraPitchYawScale = headCameraPitchYawScale->value(); + _myAvatar.setLeanScale(leanScale->value()); } void Application::pair() { diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 168fa80016..771ce8e7e5 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -79,6 +79,7 @@ Avatar::Avatar(Agent* owningAgent) : _thrust(0.0f, 0.0f, 0.0f), _speed(0.0f), _maxArmLength(0.0f), + _leanScale(0.5f), _pelvisStandingHeight(0.0f), _pelvisFloatingHeight(0.0f), _distanceToNearestAvatar(std::numeric_limits::max()), @@ -286,7 +287,7 @@ void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterfa _head.setRoll(estimatedRotation.z * AMPLIFY_ROLL); // Update torso lean distance based on accelerometer data - glm::vec3 estimatedPosition = serialInterface->getEstimatedPosition(); + glm::vec3 estimatedPosition = serialInterface->getEstimatedPosition() * _leanScale; const float TORSO_LENGTH = 0.5f; const float MAX_LEAN = 45.0f; _head.setLeanSideways(glm::clamp(glm::degrees(atanf(-estimatedPosition.x / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN)); @@ -1223,6 +1224,8 @@ void Avatar::loadData(QSettings* settings) { _voxels.setVoxelURL(settings->value("voxelURL").toUrl()); + _leanScale = loadSetting(settings, "leanScale", 0.5f); + settings->endGroup(); } @@ -1244,6 +1247,8 @@ void Avatar::saveData(QSettings* set) { set->setValue("voxelURL", _voxels.getVoxelURL()); + set->setValue("leanScale", _leanScale); + set->endGroup(); } diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 8391c81e96..34483b6d93 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -96,6 +96,7 @@ public: void setMovedHandOffset (glm::vec3 movedHandOffset ) { _movedHandOffset = movedHandOffset;} void setThrust (glm::vec3 newThrust ) { _thrust = newThrust; }; void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors);} + void setLeanScale (float scale ) { _leanScale = scale;} void setGravity (glm::vec3 gravity); void setMouseRay (const glm::vec3 &origin, const glm::vec3 &direction); void setOrientation (const glm::quat& orientation); @@ -115,6 +116,7 @@ public: float getSpeed () const { return _speed;} float getHeight () const { return _height;} AvatarMode getMode () const { return _mode;} + float getLeanScale () const { return _leanScale;} float getAbsoluteHeadYaw () const; float getAbsoluteHeadPitch () const; Head& getHead () {return _head; } @@ -182,7 +184,7 @@ private: glm::vec3 _thrust; float _speed; float _maxArmLength; - glm::quat _righting; + float _leanScale; int _driveKeys[MAX_DRIVE_KEYS]; float _pelvisStandingHeight; float _pelvisFloatingHeight; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 74fe5abd1c..cc566dd6fb 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -498,9 +498,9 @@ void runTimingTests() { } float loadSetting(QSettings* settings, const char* name, float defaultValue) { - float value = settings->value(name, 0.0f).toFloat(); + float value = settings->value(name, defaultValue).toFloat(); if (isnan(value)) { value = defaultValue; } return value; -} \ No newline at end of file +} From 178996bb8bf2789c6d9069932c81ced3fb9e7c9e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 13:30:41 -0700 Subject: [PATCH 48/71] Make sure first person mode and mirror mode are mutually exclusive. --- interface/src/Application.cpp | 13 ++++++++----- interface/src/Application.h | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e3c7ca0bdf..f76d413db9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -144,7 +144,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _viewFrustumOffsetDistance(25.0), _viewFrustumOffsetUp(0.0), _audioScope(256, 200, true), - _manualFirstPerson(false), _mouseX(0), _mouseY(0), _mousePressed(false), @@ -908,6 +907,8 @@ void Application::setHead(bool head) { if (head) { _myCamera.setMode(CAMERA_MODE_MIRROR); _myCamera.setModeShiftRate(100.0f); + _manualFirstPerson->setChecked(false); + } else { _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); _myCamera.setModeShiftRate(1.0f); @@ -925,7 +926,9 @@ void Application::setFullscreen(bool fullscreen) { } void Application::setRenderFirstPerson(bool firstPerson) { - _manualFirstPerson = firstPerson; + if (firstPerson) { + _lookingInMirror->setChecked(false); + } } void Application::setFrustumOffset(bool frustumOffset) { @@ -1250,8 +1253,8 @@ void Application::initMenu() { _renderFrameTimerOn->setChecked(false); (_renderLookatOn = renderMenu->addAction("Lookat Vectors"))->setCheckable(true); _renderLookatOn->setChecked(false); - - renderMenu->addAction("First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P)->setCheckable(true); + (_manualFirstPerson = renderMenu->addAction( + "First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P))->setCheckable(true); QMenu* toolsMenu = menuBar->addMenu("Tools"); (_renderStatsOn = toolsMenu->addAction("Stats"))->setCheckable(true); @@ -1572,7 +1575,7 @@ void Application::update(float deltaTime) { } } else { if (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) { - if (_manualFirstPerson) { + if (_manualFirstPerson->isChecked()) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); diff --git a/interface/src/Application.h b/interface/src/Application.h index 4f33f8fb1e..062954a4b7 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -186,6 +186,7 @@ private: QAction* _renderStatsOn; // Whether to show onscreen text overlay with stats QAction* _renderFrameTimerOn; // Whether to show onscreen text overlay with stats QAction* _renderLookatOn; // Whether to show lookat vectors from avatar eyes if looking at something + QAction* _manualFirstPerson; // Whether to force first-person mode QAction* _logOn; // Whether to show on-screen log QActionGroup* _voxelModeActions; // The group of voxel edit mode actions QAction* _addVoxelMode; // Whether add voxel mode is enabled @@ -249,7 +250,6 @@ private: Environment _environment; int _headMouseX, _headMouseY; - bool _manualFirstPerson; float _headCameraPitchYawScale; HandControl _handControl; From b28df1720701cf8643c91b56a020694671eb7580 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 13:51:16 -0700 Subject: [PATCH 49/71] Slight tweak: we need to call trigger in order to get the full toggle behavior. --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f76d413db9..3121ed36e0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -926,8 +926,8 @@ void Application::setFullscreen(bool fullscreen) { } void Application::setRenderFirstPerson(bool firstPerson) { - if (firstPerson) { - _lookingInMirror->setChecked(false); + if (firstPerson && _lookingInMirror->isChecked()) { + _lookingInMirror->trigger(); } } From f197b4cd6243eff01569768d394abdcf6c361af6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 14:20:28 -0700 Subject: [PATCH 50/71] Some debugging to use on the other machine. --- interface/src/Application.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3121ed36e0..4079e920b1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -826,6 +826,9 @@ void Application::terminate() { static void sendAvatarVoxelURLMessage(const QUrl& url) { uint16_t ownerID = AgentList::getInstance()->getOwnerID(); + + qDebug() << "me" << ownerID << url; + if (ownerID == UNKNOWN_AGENT_ID) { return; // we don't yet know who we are } @@ -847,6 +850,8 @@ static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataB packetData += sizeof(agentID); dataBytes -= sizeof(agentID); + qDebug() << "them" << agentID << QUrl::fromEncoded(QByteArray((char*)packetData, dataBytes)); + // make sure the agent exists Agent* agent = AgentList::getInstance()->agentWithID(agentID); if (!agent || !agent->getLinkedData()) { From e4ed9162b981d206adc148499cd78b681a47ba24 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 15:52:29 -0700 Subject: [PATCH 51/71] This should help, as well as fix another annoyance: bind to an ephemeral port, rather than a fixed one. --- interface/src/Application.cpp | 6 +----- libraries/shared/src/AgentList.cpp | 3 +-- libraries/shared/src/AgentList.h | 2 +- libraries/shared/src/UDPSocket.cpp | 9 ++++++++- libraries/shared/src/UDPSocket.h | 4 +++- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4079e920b1..d864fb86dd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -169,7 +169,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _window->setWindowTitle("Interface"); printLog("Interface Startup:\n"); - unsigned int listenPort = AGENT_SOCKET_LISTEN_PORT; + unsigned int listenPort = 0; // bind to an ephemeral port by default const char** constArgv = const_cast(argv); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); if (portStr) { @@ -827,8 +827,6 @@ void Application::terminate() { static void sendAvatarVoxelURLMessage(const QUrl& url) { uint16_t ownerID = AgentList::getInstance()->getOwnerID(); - qDebug() << "me" << ownerID << url; - if (ownerID == UNKNOWN_AGENT_ID) { return; // we don't yet know who we are } @@ -850,8 +848,6 @@ static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataB packetData += sizeof(agentID); dataBytes -= sizeof(agentID); - qDebug() << "them" << agentID << QUrl::fromEncoded(QByteArray((char*)packetData, dataBytes)); - // make sure the agent exists Agent* agent = AgentList::getInstance()->agentWithID(agentID); if (!agent || !agent->getLinkedData()) { diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 9c309bb23f..56641bd2a0 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -62,7 +62,6 @@ AgentList::AgentList(char newOwnerType, unsigned int newSocketListenPort) : _agentSocket(newSocketListenPort), _ownerType(newOwnerType), _agentTypesOfInterest(NULL), - _socketListenPort(newSocketListenPort), _ownerID(UNKNOWN_AGENT_ID), _lastAgentID(0) { pthread_mutex_init(&mutex, 0); @@ -224,7 +223,7 @@ void AgentList::sendDomainServerCheckIn() { packetPosition += packSocket(checkInPacket + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE), getLocalAddress(), - htons(_socketListenPort)); + htons(_agentSocket.getListeningPort())); // add the number of bytes for agent types of interest *(packetPosition++) = numBytesAgentsOfInterest; diff --git a/libraries/shared/src/AgentList.h b/libraries/shared/src/AgentList.h index 3007dbc8e3..1b51913928 100644 --- a/libraries/shared/src/AgentList.h +++ b/libraries/shared/src/AgentList.h @@ -58,7 +58,7 @@ public: UDPSocket* getAgentSocket() { return &_agentSocket; } - unsigned int getSocketListenPort() const { return _socketListenPort; }; + unsigned int getSocketListenPort() const { return _agentSocket.getListeningPort(); }; void(*linkedDataCreateCallback)(Agent *); diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index b7c2275635..8cd58a20bc 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -117,7 +117,7 @@ unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket) { } } -UDPSocket::UDPSocket(int listeningPort) : blocking(true) { +UDPSocket::UDPSocket(int listeningPort) : blocking(true), listeningPort(listeningPort) { init(); // create the socket handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -140,6 +140,13 @@ UDPSocket::UDPSocket(int listeningPort) : blocking(true) { return; } + // if we requested an ephemeral port, get the actual port + if (listeningPort == 0) { + socklen_t addressLength = sizeof(sockaddr_in); + getsockname(handle, (sockaddr*) &bind_address, &addressLength); + listeningPort = ntohs(bind_address.sin_port); + } + // set timeout on socket recieve to 0.5 seconds struct timeval tv; tv.tv_sec = 0; diff --git a/libraries/shared/src/UDPSocket.h b/libraries/shared/src/UDPSocket.h index b56a1cc0cf..8539ff93c2 100644 --- a/libraries/shared/src/UDPSocket.h +++ b/libraries/shared/src/UDPSocket.h @@ -23,14 +23,16 @@ public: UDPSocket(int listening_port); ~UDPSocket(); bool init(); + int getListeningPort() const { return listeningPort; } void setBlocking(bool blocking); - bool isBlocking() { return blocking; } + bool isBlocking() const { return blocking; } int send(sockaddr* destAddress, const void* data, size_t byteLength) const; int send(char* destAddress, int destPort, const void* data, size_t byteLength) const; bool receive(void* receivedData, ssize_t* receivedBytes) const; bool receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const; private: int handle; + int listeningPort; bool blocking; }; From 6dae9db01de45a04e6487f20076a30c27232c88d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 15:54:13 -0700 Subject: [PATCH 52/71] Initialize members in the right order. --- libraries/shared/src/UDPSocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index 8cd58a20bc..69cf0cfebe 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -117,7 +117,7 @@ unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket) { } } -UDPSocket::UDPSocket(int listeningPort) : blocking(true), listeningPort(listeningPort) { +UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking(true) { init(); // create the socket handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); From 19180ad9006667f7b0ea1b8ee2ea905f4b029d82 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 15:56:28 -0700 Subject: [PATCH 53/71] Put the debugging back in. --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d864fb86dd..b02afe2b0e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -827,6 +827,8 @@ void Application::terminate() { static void sendAvatarVoxelURLMessage(const QUrl& url) { uint16_t ownerID = AgentList::getInstance()->getOwnerID(); + qDebug() << "me" << ownerID << url; + if (ownerID == UNKNOWN_AGENT_ID) { return; // we don't yet know who we are } @@ -848,6 +850,8 @@ static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataB packetData += sizeof(agentID); dataBytes -= sizeof(agentID); + qDebug() << "them" << agentID << QUrl::fromEncoded(QByteArray((char*)packetData, dataBytes)); + // make sure the agent exists Agent* agent = AgentList::getInstance()->agentWithID(agentID); if (!agent || !agent->getLinkedData()) { From ccd61ee5a2d4aaac9623382baaf9e0568885947f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 16:13:44 -0700 Subject: [PATCH 54/71] Found the problem we were having: the domain server was reporting back all kinds of things as our ID. --- domain-server/src/main.cpp | 35 ++++++++++++++++++----------------- interface/src/Application.cpp | 4 ---- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index b1e2117db3..b8f66b0641 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -135,25 +135,26 @@ int main(int argc, const char * argv[]) if (numInterestTypes > 0) { // if the agent has sent no types of interest, assume they want nothing but their own ID back for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType) - && memchr(agentTypesOfInterest, agent->getType(), numInterestTypes)) { - // this is not the agent themselves - // and this is an agent of a type in the passed agent types of interest - // or the agent did not pass us any specific types they are interested in + if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType)) { + if (memchr(agentTypesOfInterest, agent->getType(), numInterestTypes)) { + // this is not the agent themselves + // and this is an agent of a type in the passed agent types of interest + // or the agent did not pass us any specific types they are interested in - if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) { - // this is an agent of which there can be multiple, just add them to the packet - // don't send avatar agents to other avatars, that will come from avatar mixer - if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) { - currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent)); - } + if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) { + // this is an agent of which there can be multiple, just add them to the packet + // don't send avatar agents to other avatars, that will come from avatar mixer + if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) { + currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent)); + } - } else { - // solo agent, we need to only send newest - if (newestSoloAgents[agent->getType()] == NULL || - newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) { - // we have to set the newer solo agent to add it to the broadcast later - newestSoloAgents[agent->getType()] = &(*agent); + } else { + // solo agent, we need to only send newest + if (newestSoloAgents[agent->getType()] == NULL || + newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) { + // we have to set the newer solo agent to add it to the broadcast later + newestSoloAgents[agent->getType()] = &(*agent); + } } } } else { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b02afe2b0e..d864fb86dd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -827,8 +827,6 @@ void Application::terminate() { static void sendAvatarVoxelURLMessage(const QUrl& url) { uint16_t ownerID = AgentList::getInstance()->getOwnerID(); - qDebug() << "me" << ownerID << url; - if (ownerID == UNKNOWN_AGENT_ID) { return; // we don't yet know who we are } @@ -850,8 +848,6 @@ static void processAvatarVoxelURLMessage(unsigned char *packetData, size_t dataB packetData += sizeof(agentID); dataBytes -= sizeof(agentID); - qDebug() << "them" << agentID << QUrl::fromEncoded(QByteArray((char*)packetData, dataBytes)); - // make sure the agent exists Agent* agent = AgentList::getInstance()->agentWithID(agentID); if (!agent || !agent->getLinkedData()) { From 7570329867220b5c07d218359f11c8ced8a9907a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 12 Jun 2013 16:28:37 -0700 Subject: [PATCH 55/71] This appears still to be broken, but you know what? We already have the agent pointer; why not just get the ID from that? --- domain-server/src/main.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index b8f66b0641..d84dd64a1b 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -94,8 +94,6 @@ int main(int argc, const char * argv[]) agentList->startSilentAgentRemovalThread(); - uint16_t packetAgentID = 0; - while (true) { if (agentList->getAgentSocket()->receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes) && (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_HEADER_DOMAIN_LIST_REQUEST)) { @@ -163,9 +161,6 @@ int main(int argc, const char * argv[]) // this is the agent, just update last receive to now agent->setLastHeardMicrostamp(timeNow); - // grab the ID for this agent so we can send it back with the packet - packetAgentID = agent->getAgentID(); - if (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY && memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) { agent->setWakeMicrostamp(timeNow); @@ -182,7 +177,7 @@ int main(int argc, const char * argv[]) } // add the agent ID to the end of the pointer - currentBufferPos += packAgentId(currentBufferPos, packetAgentID); + currentBufferPos += packAgentId(currentBufferPos, newAgent->getAgentID()); // send the constructed list back to this agent agentList->getAgentSocket()->send((sockaddr*) &agentPublicAddress, From a5a0df09cb85a4278fca92eda24a037b35a0017d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Jun 2013 16:36:55 -0700 Subject: [PATCH 56/71] removed grab voxel rendering --- animation-server/src/main.cpp | 1 - interface/src/Application.cpp | 2 +- interface/src/Application.h | 8 ++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index c02e8e8383..37dd301d1c 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -244,7 +244,6 @@ static void renderMovingBug() { } - float intensity = 0.5f; float intensityIncrement = 0.1f; const float MAX_INTENSITY = 1.0f; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8f78c2f770..925d629933 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1991,7 +1991,7 @@ void Application::displaySide(Camera& whichCamera) { // Enable to show line from me to the voxel I am touching //renderLineToTouchedVoxel(); - renderThrustAtVoxel(_voxelThrust); + //renderThrustAtVoxel(_voxelThrust); // draw a red sphere float sphereRadius = 0.25f; diff --git a/interface/src/Application.h b/interface/src/Application.h index ac45415d43..655268024b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -95,6 +95,9 @@ private slots: void setRenderFirstPerson(bool firstPerson); + void renderThrustAtVoxel(glm::vec3 thrust); + void renderLineToTouchedVoxel(); + void setFrustumOffset(bool frustumOffset); void cycleFrustumRenderMode(); @@ -143,10 +146,7 @@ private: void displayStats(); void renderViewFrustum(ViewFrustum& viewFrustum); - - void renderLineToTouchedVoxel(); - void renderThrustAtVoxel(glm::vec3 thrust); - + void setupPaintingVoxel(); void shiftPaintingColor(); void maybeEditVoxelUnderCursor(); From c0ba2aeebea21e5997b16d6342ce2e2763994c56 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 12 Jun 2013 23:45:59 -0700 Subject: [PATCH 57/71] Added jumping, tuned friction model, tuned thrust --- interface/src/Application.cpp | 6 ++- interface/src/Avatar.cpp | 92 ++++++++++++++++++++--------------- interface/src/Avatar.h | 2 + 3 files changed, 60 insertions(+), 40 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 925d629933..230e523d34 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -510,6 +510,9 @@ void Application::keyPressEvent(QKeyEvent* event) { break; case Qt::Key_E: + if (!_myAvatar.getDriveKeys(UP)) { + _myAvatar.jump(); + } _myAvatar.setDriveKeys(UP, 1); break; @@ -1450,12 +1453,11 @@ void Application::update(float deltaTime) { _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); // If we are dragging on a voxel, add thrust according to the amount the mouse is dragging - const float VOXEL_GRAB_THRUST = 10.0f; + const float VOXEL_GRAB_THRUST = 5.0f; if (_mousePressed && (_mouseVoxel.s != 0)) { glm::vec2 mouseDrag(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY); glm::quat orientation = _myAvatar.getOrientation(); glm::vec3 front = orientation * IDENTITY_FRONT; - glm::vec3 right = orientation * IDENTITY_RIGHT; glm::vec3 up = orientation * IDENTITY_UP; glm::vec3 towardVoxel = getMouseVoxelWorldCoordinates(_mouseVoxelDragging) - _myAvatar.getCameraPosition(); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 9c45d5a1c8..adbe3358da 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -77,6 +77,7 @@ Avatar::Avatar(Agent* owningAgent) : _handHoldingPosition(0.0f, 0.0f, 0.0f), _velocity(0.0f, 0.0f, 0.0f), _thrust(0.0f, 0.0f, 0.0f), + _shouldJump(false), _speed(0.0f), _maxArmLength(0.0f), _leanScale(0.5f), @@ -412,28 +413,38 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { glm::vec3 up = orientation * IDENTITY_UP; // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) - const float THRUST_MAG = 600.0f; + const float THRUST_MAG_UP = 800.0f; + const float THRUST_MAG_DOWN = 200.f; + const float THRUST_MAG_FWD = 300.f; + const float THRUST_MAG_BACK = 150.f; + const float THRUST_MAG_LATERAL = 200.f; + const float THRUST_JUMP = 100.f; if (!_owningAgent) { // Add Thrusts from keyboard - if (_driveKeys[FWD ]) {_thrust += THRUST_MAG * deltaTime * front;} - if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG * deltaTime * front;} - if (_driveKeys[RIGHT ]) {_thrust += THRUST_MAG * deltaTime * right;} - if (_driveKeys[LEFT ]) {_thrust -= THRUST_MAG * deltaTime * right;} - if (_driveKeys[UP ]) {_thrust += THRUST_MAG * deltaTime * up;} - if (_driveKeys[DOWN ]) {_thrust -= THRUST_MAG * deltaTime * up;} + if (_driveKeys[FWD ]) {_thrust += THRUST_MAG_FWD * deltaTime * front;} + if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG_BACK * deltaTime * front;} + if (_driveKeys[RIGHT ]) {_thrust += THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[LEFT ]) {_thrust -= THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[UP ]) {_thrust += THRUST_MAG_UP * deltaTime * up;} + if (_driveKeys[DOWN ]) {_thrust -= THRUST_MAG_DOWN * deltaTime * up;} if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;} + if (_shouldJump) { + _thrust += THRUST_JUMP * up; + _shouldJump = false; + } // Add thrusts from Transmitter if (transmitter) { transmitter->checkForLostTransmitter(); glm::vec3 rotation = transmitter->getEstimatedRotation(); const float TRANSMITTER_MIN_RATE = 1.f; const float TRANSMITTER_MIN_YAW_RATE = 4.f; - const float TRANSMITTER_LATERAL_FORCE_SCALE = 25.f; - const float TRANSMITTER_FWD_FORCE_SCALE = 100.f; + const float TRANSMITTER_LATERAL_FORCE_SCALE = 5.f; + const float TRANSMITTER_FWD_FORCE_SCALE = 25.f; + const float TRANSMITTER_UP_FORCE_SCALE = 100.f; const float TRANSMITTER_YAW_SCALE = 10.0f; const float TRANSMITTER_LIFT_SCALE = 3.f; const float TOUCH_POSITION_RANGE_HALF = 32767.f; @@ -447,7 +458,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _bodyYawDelta += rotation.y * TRANSMITTER_YAW_SCALE * deltaTime; } if (transmitter->getTouchState()->state == 'D') { - _thrust += THRUST_MAG * + _thrust += TRANSMITTER_UP_FORCE_SCALE * (float)(transmitter->getTouchState()->y - TOUCH_POSITION_RANGE_HALF) / TOUCH_POSITION_RANGE_HALF * TRANSMITTER_LIFT_SCALE * deltaTime * @@ -469,9 +480,31 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { // add thrust to velocity _velocity += _thrust * deltaTime; - // Zero thrust out now that we've added it to velocity in this frame - _thrust = glm::vec3(0, 0, 0); + // Decay velocity. If velocity is really low, increase decay to simulate static friction + const float VELOCITY_DECAY_UNDER_THRUST = 0.0; + const float VELOCITY_FAST_DECAY = 0.8; + const float VELOCITY_SLOW_DECAY = 8.0; + const float VELOCITY_HALT_DECAY = 100.0; + const float VELOCITY_FAST_THRESHOLD = 2.0f; + const float VELOCITY_HALT_THRESHOLD = 0.15f; + float decayConstant, decay; + if (glm::length(_thrust) > 0.f) { + decayConstant = VELOCITY_DECAY_UNDER_THRUST; + } else if (glm::length(_velocity) > VELOCITY_FAST_THRESHOLD) { + decayConstant = VELOCITY_FAST_DECAY; + } else if (glm::length(_velocity) > VELOCITY_HALT_THRESHOLD) { + decayConstant = VELOCITY_SLOW_DECAY; + } else { + decayConstant = VELOCITY_HALT_DECAY; + } + + decay = glm::clamp(1.0f - decayConstant * deltaTime, 0.0f, 1.0f); + _velocity *= decay; + + // update position by velocity + _position += _velocity * deltaTime; + // calculate speed _speed = glm::length(_velocity); @@ -494,27 +527,11 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { //the following will be used to make the avatar upright no matter what gravity is setOrientation(computeRotationFromBodyToWorldUp(tiltDecay) * orientation); - // update position by velocity - _position += _velocity * deltaTime; - - // decay velocity - const float VELOCITY_DECAY = 0.9; - float decay = 1.0 - VELOCITY_DECAY * deltaTime; - if ( decay < 0.0 ) { - _velocity = glm::vec3( 0.0f, 0.0f, 0.0f ); - } else { - _velocity *= decay; - } - // If another avatar is near, dampen velocity as a function of closeness if (_distanceToNearestAvatar < PERIPERSONAL_RADIUS) { float closeness = 1.0f - (_distanceToNearestAvatar / PERIPERSONAL_RADIUS); - float drag = 1.0f - closeness * AVATAR_BRAKING_STRENGTH * deltaTime; - if ( drag > 0.0f ) { - _velocity *= drag; - } else { - _velocity = glm::vec3( 0.0f, 0.0f, 0.0f ); - } + float avatarDrag = glm::clamp(1.0f - closeness * AVATAR_BRAKING_STRENGTH * deltaTime, 0.0f, 1.0f); + _velocity *= avatarDrag; } // Compute instantaneous acceleration @@ -577,6 +594,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { // set head lookat position if (!_owningAgent) { + //if (_camera) if (_interactingOther) { _head.setLookAtPosition(_interactingOther->calculateAverageEyePosition()); } else { @@ -596,6 +614,10 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } else { _mode = AVATAR_MODE_INTERACTING; } + + // Zero thrust out now that we've added it to velocity in this frame + _thrust = glm::vec3(0, 0, 0); + } void Avatar::checkForMouseRayTouching() { @@ -798,20 +820,14 @@ void Avatar::updateCollisionWithVoxels() { void Avatar::applyCollisionWithScene(const glm::vec3& penetration) { _position -= penetration; - static float STATIC_FRICTION_VELOCITY = 0.15f; - static float STATIC_FRICTION_DAMPING = 0.0f; static float KINETIC_FRICTION_DAMPING = 0.95f; - + static float ELASTIC_COLLISION_FACTOR = 1.4f; // 1.0 = inelastic, > 2.0 = pinball bumper! // cancel out the velocity component in the direction of penetration float penetrationLength = glm::length(penetration); if (penetrationLength > EPSILON) { glm::vec3 direction = penetration / penetrationLength; - _velocity -= glm::dot(_velocity, direction) * direction; + _velocity -= glm::dot(_velocity, direction) * direction * ELASTIC_COLLISION_FACTOR; _velocity *= KINETIC_FRICTION_DAMPING; - // If velocity is quite low, apply static friction that takes away energy - if (glm::length(_velocity) < STATIC_FRICTION_VELOCITY) { - _velocity *= STATIC_FRICTION_DAMPING; - } } } diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index ef42ee4c73..5be04b06c3 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -131,6 +131,7 @@ public: // Set what driving keys are being pressed to control thrust levels void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; bool getDriveKeys(int key) { return _driveKeys[key]; }; + void jump() { _shouldJump = true; }; // Set/Get update the thrust that will move the avatar around void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; @@ -183,6 +184,7 @@ private: glm::vec3 _handHoldingPosition; glm::vec3 _velocity; glm::vec3 _thrust; + bool _shouldJump; float _speed; float _maxArmLength; float _leanScale; From db729a04aa953668d993dd9e93e02402e397e760 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Jun 2013 11:11:59 -0700 Subject: [PATCH 58/71] Converted double timestamps to long long (64 bit integers), fixed bug with updating agent timestamps. --- animation-server/src/main.cpp | 6 +- audio-mixer/src/main.cpp | 2 +- domain-server/src/main.cpp | 56 +++++++++--------- eve/src/main.cpp | 4 +- injector/src/main.cpp | 2 +- interface/src/Application.cpp | 5 +- interface/src/VoxelSystem.cpp | 14 ++--- libraries/audio/src/AudioInjector.cpp | 2 +- libraries/shared/src/Agent.cpp | 2 + libraries/shared/src/Agent.h | 12 ++-- libraries/shared/src/AgentList.cpp | 6 +- libraries/shared/src/PerfStat.cpp | 2 +- libraries/shared/src/PerfStat.h | 2 +- libraries/shared/src/SharedUtil.cpp | 8 +-- libraries/shared/src/SharedUtil.h | 4 +- libraries/shared/src/SimpleMovingAverage.h | 2 +- libraries/voxels/src/VoxelNode.h | 4 +- voxel-server/src/main.cpp | 66 +++++++++++----------- 18 files changed, 99 insertions(+), 100 deletions(-) diff --git a/animation-server/src/main.cpp b/animation-server/src/main.cpp index c02e8e8383..bceb276a8a 100644 --- a/animation-server/src/main.cpp +++ b/animation-server/src/main.cpp @@ -644,14 +644,14 @@ void* animateVoxels(void* args) { sendDanceFloor(); } - double end = usecTimestampNow(); - double elapsedSeconds = (end - ::start) / 1000000.0; + long long end = usecTimestampNow(); + long long elapsedSeconds = (end - ::start) / 1000000; if (::shouldShowPacketsPerSecond) { printf("packetsSent=%ld, bytesSent=%ld pps=%f bps=%f\n",packetsSent,bytesSent, (float)(packetsSent/elapsedSeconds),(float)(bytesSent/elapsedSeconds)); } // dynamically sleep until we need to fire off the next set of voxels - double usecToSleep = ANIMATE_VOXELS_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSendTime)); + long long usecToSleep = ANIMATE_VOXELS_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSendTime)); if (usecToSleep > 0) { usleep(usecToSleep); diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index c9ea474354..fbcba0979f 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -318,7 +318,7 @@ int main(int argc, const char* argv[]) { } } - double usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); + long long usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); if (usecToSleep > 0) { usleep(usecToSleep); diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index d84dd64a1b..67c1123205 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -133,37 +133,26 @@ int main(int argc, const char * argv[]) if (numInterestTypes > 0) { // if the agent has sent no types of interest, assume they want nothing but their own ID back for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType)) { - if (memchr(agentTypesOfInterest, agent->getType(), numInterestTypes)) { - // this is not the agent themselves - // and this is an agent of a type in the passed agent types of interest - // or the agent did not pass us any specific types they are interested in - - if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) { - // this is an agent of which there can be multiple, just add them to the packet - // don't send avatar agents to other avatars, that will come from avatar mixer - if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) { - currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent)); - } - - } else { - // solo agent, we need to only send newest - if (newestSoloAgents[agent->getType()] == NULL || - newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) { - // we have to set the newer solo agent to add it to the broadcast later - newestSoloAgents[agent->getType()] = &(*agent); - } + if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType) && + memchr(agentTypesOfInterest, agent->getType(), numInterestTypes)) { + // this is not the agent themselves + // and this is an agent of a type in the passed agent types of interest + // or the agent did not pass us any specific types they are interested in + + if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) { + // this is an agent of which there can be multiple, just add them to the packet + // don't send avatar agents to other avatars, that will come from avatar mixer + if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) { + currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent)); } - } - } else { - double timeNow = usecTimestampNow(); - // this is the agent, just update last receive to now - agent->setLastHeardMicrostamp(timeNow); - - if (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY - && memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) { - agent->setWakeMicrostamp(timeNow); + } else { + // solo agent, we need to only send newest + if (newestSoloAgents[agent->getType()] == NULL || + newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) { + // we have to set the newer solo agent to add it to the broadcast later + newestSoloAgents[agent->getType()] = &(*agent); + } } } } @@ -175,6 +164,15 @@ int main(int argc, const char * argv[]) currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, soloAgent->second); } } + + // update last receive to now + long long timeNow = usecTimestampNow(); + newAgent->setLastHeardMicrostamp(timeNow); + + if (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY + && memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) { + newAgent->setWakeMicrostamp(timeNow); + } // add the agent ID to the end of the pointer currentBufferPos += packAgentId(currentBufferPos, newAgent->getAgentID()); diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 387c72633b..9310e2b316 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -128,7 +128,7 @@ int main(int argc, const char* argv[]) { broadcastPacket[0] = PACKET_HEADER_HEAD_DATA; timeval thisSend; - double numMicrosecondsSleep = 0; + long long numMicrosecondsSleep = 0; int handStateTimer = 0; @@ -212,4 +212,4 @@ int main(int argc, const char* argv[]) { // stop the agent list's threads agentList->stopPingUnknownAgentsThread(); agentList->stopSilentAgentRemovalThread(); -} \ No newline at end of file +} diff --git a/injector/src/main.cpp b/injector/src/main.cpp index f2e87990d1..a0c07179f7 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -187,7 +187,7 @@ int main(int argc, char* argv[]) { unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO; timeval thisSend; - double numMicrosecondsSleep = 0; + long long numMicrosecondsSleep = 0; timeval lastDomainServerCheckIn = {}; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d864fb86dd..e69e40f527 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2078,9 +2078,8 @@ void Application::displayOverlay() { // Show on-screen msec timer if (_renderFrameTimerOn->isChecked()) { char frameTimer[10]; - double mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5); - mSecsNow = mSecsNow - floor(mSecsNow / 1000.0) * 1000.0; - sprintf(frameTimer, "%3.0f\n", mSecsNow); + long long mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5); + sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000)); drawtext(_glWidget->width() - 100, _glWidget->height() - 20, 0.30, 0, 1.0, 0, frameTimer, 0, 0, 0); drawtext(_glWidget->width() - 102, _glWidget->height() - 22, 0.30, 0, 1.0, 0, frameTimer, 1, 1, 1); } diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 9cde8906be..716fe708a3 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -165,15 +165,15 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { void VoxelSystem::setupNewVoxelsForDrawing() { PerformanceWarning warn(_renderWarningsOn, "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated - double start = usecTimestampNow(); - double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0; + long long start = usecTimestampNow(); + long long sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging if (!iAmDebugging && sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { return; // bail early, it hasn't been long enough since the last time we ran } - double sinceLastViewCulling = (start - _lastViewCulling) / 1000.0; + long long sinceLastViewCulling = (start - _lastViewCulling) / 1000; // If the view frustum is no longer changing, but has changed, since last time, then remove nodes that are out of view if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) && !isViewChanging() && hasViewChanged()) { @@ -189,8 +189,8 @@ void VoxelSystem::setupNewVoxelsForDrawing() { // VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary. cleanupRemovedVoxels(); - double endViewCulling = usecTimestampNow(); - _lastViewCullingElapsed = (endViewCulling - start) / 1000.0; + long long endViewCulling = usecTimestampNow(); + _lastViewCullingElapsed = (endViewCulling - start) / 1000; } bool didWriteFullVBO = _writeRenderFullVBO; @@ -226,8 +226,8 @@ void VoxelSystem::setupNewVoxelsForDrawing() { pthread_mutex_unlock(&_bufferWriteLock); - double end = usecTimestampNow(); - double elapsedmsec = (end - start) / 1000.0; + long long end = usecTimestampNow(); + long long elapsedmsec = (end - start) / 1000; _setupNewVoxelsForDrawingLastFinished = end; _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index f9f1bcc094..24e0a369d5 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -115,7 +115,7 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket)); - double usecToSleep = usecTimestamp(&startTime) + (++nextFrame * INJECT_INTERVAL_USECS) - usecTimestampNow(); + long long usecToSleep = usecTimestamp(&startTime) + (++nextFrame * INJECT_INTERVAL_USECS) - usecTimestampNow(); if (usecToSleep > 0) { usleep(usecToSleep); } diff --git a/libraries/shared/src/Agent.cpp b/libraries/shared/src/Agent.cpp index 4556f670d6..88d0f901f2 100644 --- a/libraries/shared/src/Agent.cpp +++ b/libraries/shared/src/Agent.cpp @@ -6,6 +6,8 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +#include "stdio.h" + #include #include "Agent.h" #include "AgentTypes.h" diff --git a/libraries/shared/src/Agent.h b/libraries/shared/src/Agent.h index 5201fd9048..18d42fdf3d 100644 --- a/libraries/shared/src/Agent.h +++ b/libraries/shared/src/Agent.h @@ -37,11 +37,11 @@ public: uint16_t getAgentID() const { return _agentID; } void setAgentID(uint16_t agentID) { _agentID = agentID;} - double getWakeMicrostamp() const { return _wakeMicrostamp; } - void setWakeMicrostamp(double wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; } + long long getWakeMicrostamp() const { return _wakeMicrostamp; } + void setWakeMicrostamp(long long wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; } - double getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } - void setLastHeardMicrostamp(double lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } + long long getLastHeardMicrostamp() const { return _lastHeardMicrostamp; } + void setLastHeardMicrostamp(long long lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; } sockaddr* getPublicSocket() const { return _publicSocket; } void setPublicSocket(sockaddr* publicSocket) { _publicSocket = publicSocket; } @@ -71,8 +71,8 @@ private: char _type; uint16_t _agentID; - double _wakeMicrostamp; - double _lastHeardMicrostamp; + long long _wakeMicrostamp; + long long _lastHeardMicrostamp; sockaddr* _publicSocket; sockaddr* _localSocket; sockaddr* _activeSocket; diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 56641bd2a0..e1b4bd9d63 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -392,7 +392,7 @@ void *pingUnknownAgents(void *args) { } } - double usecToSleep = PING_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSend)); + long long usecToSleep = PING_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSend)); if (usecToSleep > 0) { usleep(usecToSleep); @@ -413,7 +413,7 @@ void AgentList::stopPingUnknownAgentsThread() { void *removeSilentAgents(void *args) { AgentList* agentList = (AgentList*) args; - double checkTimeUSecs, sleepTime; + long long checkTimeUSecs, sleepTime; while (!silentAgentThreadStopFlag) { checkTimeUSecs = usecTimestampNow(); @@ -422,7 +422,7 @@ void *removeSilentAgents(void *args) { if ((checkTimeUSecs - agent->getLastHeardMicrostamp()) > AGENT_SILENCE_THRESHOLD_USECS && agent->getType() != AGENT_TYPE_VOXEL_SERVER) { - + printLog("Killed "); Agent::printLog(*agent); diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 3c30c62993..2de5aa2816 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -104,7 +104,7 @@ int PerfStat::DumpStats(char** array) { // Destructor handles recording all of our stats PerformanceWarning::~PerformanceWarning() { - double end = usecTimestampNow(); + long long end = usecTimestampNow(); double elapsedmsec = (end - _start) / 1000.0; if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) { if (elapsedmsec > 1000) { diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index 8898899960..f57d49aa46 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -84,7 +84,7 @@ typedef std::map >::iterator class PerformanceWarning { private: - double _start; + long long _start; const char* _message; bool _renderWarningsOn; bool _alwaysDisplay; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 697719b36d..0ec2c6e302 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -22,14 +22,14 @@ #include #endif -double usecTimestamp(timeval *time) { - return (time->tv_sec * 1000000.0 + time->tv_usec); +long long usecTimestamp(timeval *time) { + return (time->tv_sec * 1000000 + time->tv_usec); } -double usecTimestampNow() { +long long usecTimestampNow() { timeval now; gettimeofday(&now, NULL); - return (now.tv_sec * 1000000.0 + now.tv_usec); + return (now.tv_sec * 1000000 + now.tv_usec); } float randFloat () { diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 28c4adb296..e227137470 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -36,8 +36,8 @@ static const float DECIMETER = 0.1f; static const float CENTIMETER = 0.01f; static const float MILLIIMETER = 0.001f; -double usecTimestamp(timeval *time); -double usecTimestampNow(); +long long usecTimestamp(timeval *time); +long long usecTimestampNow(); float randFloat(); int randIntInRange (int min, int max); diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h index e24b639133..b1d0709342 100644 --- a/libraries/shared/src/SimpleMovingAverage.h +++ b/libraries/shared/src/SimpleMovingAverage.h @@ -25,7 +25,7 @@ public: float getAverageSampleValuePerSecond(); private: int _numSamples; - double _lastEventTimestamp; + long long _lastEventTimestamp; float _average; float _eventDeltaAverage; diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 952ad15bb7..8f71ef64f1 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -29,7 +29,7 @@ private: #endif glBufferIndex _glBufferIndex; bool _isDirty; - double _lastChanged; + long long _lastChanged; bool _shouldRender; bool _isStagedForDeletion; AABox _box; @@ -80,7 +80,7 @@ public: void printDebugDetails(const char* label) const; bool isDirty() const { return _isDirty; }; void clearDirtyBit() { _isDirty = false; }; - bool hasChangedSince(double time) const { return (_lastChanged > time); }; + bool hasChangedSince(long long time) const { return (_lastChanged > time); }; void markWithChangedTime() { _lastChanged = usecTimestampNow(); }; void handleSubtreeChanged(VoxelTree* myTree); diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 1f6a386eda..aae631bb16 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -32,7 +32,7 @@ const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo"; const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo"; -const double VOXEL_PERSIST_INTERVAL = 1000.0 * 30; // every 30 seconds +const long long VOXEL_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds const int VOXEL_LISTEN_PORT = 40106; @@ -118,7 +118,7 @@ void resInVoxelDistributor(AgentList* agentList, bool searchReset = false; int searchLoops = 0; int searchLevelWas = agentData->getMaxSearchLevel(); - double start = usecTimestampNow(); + long long start = usecTimestampNow(); while (!searchReset && agentData->nodeBag.isEmpty()) { searchLoops++; @@ -137,19 +137,19 @@ void resInVoxelDistributor(AgentList* agentList, } } } - double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; + long long end = usecTimestampNow(); + int elapsedmsec = (end - start)/1000; if (elapsedmsec > 100) { if (elapsedmsec > 1000) { - double elapsedsec = (end - start)/1000000.0; - printf("WARNING! searchForColoredNodes() took %lf seconds to identify %d nodes at level %d in %d loops\n", + int elapsedsec = (end - start)/1000000; + printf("WARNING! searchForColoredNodes() took %d seconds to identify %d nodes at level %d in %d loops\n", elapsedsec, agentData->nodeBag.count(), searchLevelWas, searchLoops); } else { - printf("WARNING! searchForColoredNodes() took %lf milliseconds to identify %d nodes at level %d in %d loops\n", + printf("WARNING! searchForColoredNodes() took %d milliseconds to identify %d nodes at level %d in %d loops\n", elapsedmsec, agentData->nodeBag.count(), searchLevelWas, searchLoops); } } else if (::debugVoxelSending) { - printf("searchForColoredNodes() took %lf milliseconds to identify %d nodes at level %d in %d loops\n", + printf("searchForColoredNodes() took %d milliseconds to identify %d nodes at level %d in %d loops\n", elapsedmsec, agentData->nodeBag.count(), searchLevelWas, searchLoops); } @@ -161,7 +161,7 @@ void resInVoxelDistributor(AgentList* agentList, int packetsSentThisInterval = 0; int truePacketsSent = 0; int trueBytesSent = 0; - double start = usecTimestampNow(); + long long start = usecTimestampNow(); bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { @@ -206,19 +206,19 @@ void resInVoxelDistributor(AgentList* agentList, trueBytesSent += envPacketLength; truePacketsSent++; } - double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; + long long end = usecTimestampNow(); + int elapsedmsec = (end - start)/1000; if (elapsedmsec > 100) { if (elapsedmsec > 1000) { - double elapsedsec = (end - start)/1000000.0; - printf("WARNING! packetLoop() took %lf seconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n", + int elapsedsec = (end - start)/1000000; + printf("WARNING! packetLoop() took %d seconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n", elapsedsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count()); } else { - printf("WARNING! packetLoop() took %lf milliseconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n", + printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n", elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count()); } } else if (::debugVoxelSending) { - printf("packetLoop() took %lf milliseconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n", + printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n", elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count()); } @@ -245,7 +245,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, pthread_mutex_lock(&::treeLock); int maxLevelReached = 0; - double start = usecTimestampNow(); + long long start = usecTimestampNow(); // FOR NOW... agent tells us if it wants to receive only view frustum deltas bool wantDelta = agentData->getWantDelta(); @@ -281,19 +281,19 @@ void deepestLevelVoxelDistributor(AgentList* agentList, } } - double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; + long long end = usecTimestampNow(); + int elapsedmsec = (end - start)/1000; if (elapsedmsec > 100) { if (elapsedmsec > 1000) { - double elapsedsec = (end - start)/1000000.0; - printf("WARNING! searchForColoredNodes() took %lf seconds to identify %d nodes at level %d\n", + int elapsedsec = (end - start)/1000000; + printf("WARNING! searchForColoredNodes() took %d seconds to identify %d nodes at level %d\n", elapsedsec, agentData->nodeBag.count(), maxLevelReached); } else { - printf("WARNING! searchForColoredNodes() took %lf milliseconds to identify %d nodes at level %d\n", + printf("WARNING! searchForColoredNodes() took %d milliseconds to identify %d nodes at level %d\n", elapsedmsec, agentData->nodeBag.count(), maxLevelReached); } } else if (::debugVoxelSending) { - printf("searchForColoredNodes() took %lf milliseconds to identify %d nodes at level %d\n", + printf("searchForColoredNodes() took %d milliseconds to identify %d nodes at level %d\n", elapsedmsec, agentData->nodeBag.count(), maxLevelReached); } @@ -304,7 +304,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, int packetsSentThisInterval = 0; int truePacketsSent = 0; int trueBytesSent = 0; - double start = usecTimestampNow(); + long long start = usecTimestampNow(); bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { @@ -351,19 +351,19 @@ void deepestLevelVoxelDistributor(AgentList* agentList, truePacketsSent++; } - double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; + long long end = usecTimestampNow(); + int elapsedmsec = (end - start)/1000; if (elapsedmsec > 100) { if (elapsedmsec > 1000) { - double elapsedsec = (end - start)/1000000.0; - printf("WARNING! packetLoop() took %lf seconds to generate %d bytes in %d packets %d nodes still to send\n", + int elapsedsec = (end - start)/1000000; + printf("WARNING! packetLoop() took %d seconds to generate %d bytes in %d packets %d nodes still to send\n", elapsedsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count()); } else { - printf("WARNING! packetLoop() took %lf milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", + printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count()); } } else if (::debugVoxelSending) { - printf("packetLoop() took %lf milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", + printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", elapsedmsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count()); } @@ -380,10 +380,10 @@ void deepestLevelVoxelDistributor(AgentList* agentList, pthread_mutex_unlock(&::treeLock); } -double lastPersistVoxels = 0; +long long lastPersistVoxels = 0; void persistVoxelsWhenDirty() { - double now = usecTimestampNow(); - double sinceLastTime = (now - ::lastPersistVoxels) / 1000.0; + long long now = usecTimestampNow(); + long long sinceLastTime = (now - ::lastPersistVoxels) / 1000; // check the dirty bit and persist here... if (::wantVoxelPersist && ::serverTree.isDirty() && sinceLastTime > VOXEL_PERSIST_INTERVAL) { @@ -428,7 +428,7 @@ void *distributeVoxelsToListeners(void *args) { } // dynamically sleep until we need to fire off the next set of voxels - double usecToSleep = VOXEL_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSendTime)); + long long usecToSleep = VOXEL_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSendTime)); if (usecToSleep > 0) { usleep(usecToSleep); From 61b1a2f995d1e9cf5908479d87763098a53272a3 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 13 Jun 2013 11:31:41 -0700 Subject: [PATCH 59/71] First person to third person transition driven by velocity, changes to make moving and flying physics more fun. --- interface/src/Application.cpp | 33 ++--- interface/src/Avatar.cpp | 233 ++++++++++++++++++++-------------- interface/src/Avatar.h | 11 +- 3 files changed, 159 insertions(+), 118 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 230e523d34..c5d913c65e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -62,8 +62,6 @@ using namespace std; -const bool TESTING_AVATAR_TOUCH = false; - // Starfield information static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; @@ -1600,30 +1598,27 @@ void Application::update(float deltaTime) { _myAvatar.simulate(deltaTime, NULL); } - if (TESTING_AVATAR_TOUCH) { - if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { - _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); - _myCamera.setModeShiftRate(1.0f); - } - } else { if (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) { if (_manualFirstPerson->isChecked()) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); } - } else { - if (_myAvatar.getIsNearInteractingOther()) { - if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { - _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); - _myCamera.setModeShiftRate(1.0f); - } - } else { - if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { - _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); - _myCamera.setModeShiftRate(1.0f); - } + } else { + const float THIRD_PERSON_SHIFT_VELOCITY = 2.0f; + const float TIME_BEFORE_SHIFT_INTO_FIRST_PERSON = 0.75f; + const float TIME_BEFORE_SHIFT_INTO_THIRD_PERSON = 0.1f; + + if ((_myAvatar.getElapsedTimeStopped() > TIME_BEFORE_SHIFT_INTO_FIRST_PERSON) + && (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON)) { + _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); + _myCamera.setModeShiftRate(1.0f); } + if ((_myAvatar.getSpeed() > THIRD_PERSON_SHIFT_VELOCITY) + && (_myAvatar.getElapsedTimeMoving() > TIME_BEFORE_SHIFT_INTO_THIRD_PERSON) + && (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON)) { + _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); + _myCamera.setModeShiftRate(1000.0f); } } } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index adbe3358da..c55f082be5 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -90,6 +90,9 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _isMouseTurningRight(false), + _elapsedTimeMoving(0.0f), + _elapsedTimeStopped(0.0f), + _elapsedTimeSinceCollision(0.0f), _voxels(this) { // give the pointer to our head to inherited _headData variable from AvatarData @@ -336,14 +339,109 @@ void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int scree } } +void Avatar::updateThrust(float deltaTime, Transmitter * transmitter) { + // + // Gather thrust information from keyboard and sensors to apply to avatar motion + // + glm::quat orientation = getOrientation(); + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; + + const float THRUST_MAG_UP = 800.0f; + const float THRUST_MAG_DOWN = 200.f; + const float THRUST_MAG_FWD = 300.f; + const float THRUST_MAG_BACK = 150.f; + const float THRUST_MAG_LATERAL = 200.f; + const float THRUST_JUMP = 65.f; + + // Add Thrusts from keyboard + if (_driveKeys[FWD ]) {_thrust += THRUST_MAG_FWD * deltaTime * front;} + if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG_BACK * deltaTime * front;} + if (_driveKeys[RIGHT ]) {_thrust += THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[LEFT ]) {_thrust -= THRUST_MAG_LATERAL * deltaTime * right;} + if (_driveKeys[UP ]) {_thrust += THRUST_MAG_UP * deltaTime * up;} + if (_driveKeys[DOWN ]) {_thrust -= THRUST_MAG_DOWN * deltaTime * up;} + if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} + if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;} + + // Add one time jumping force if requested + if (_shouldJump) { + _thrust += THRUST_JUMP * up; + _shouldJump = false; + } + + // Add thrusts from Transmitter + if (transmitter) { + transmitter->checkForLostTransmitter(); + glm::vec3 rotation = transmitter->getEstimatedRotation(); + const float TRANSMITTER_MIN_RATE = 1.f; + const float TRANSMITTER_MIN_YAW_RATE = 4.f; + const float TRANSMITTER_LATERAL_FORCE_SCALE = 5.f; + const float TRANSMITTER_FWD_FORCE_SCALE = 25.f; + const float TRANSMITTER_UP_FORCE_SCALE = 100.f; + const float TRANSMITTER_YAW_SCALE = 10.0f; + const float TRANSMITTER_LIFT_SCALE = 3.f; + const float TOUCH_POSITION_RANGE_HALF = 32767.f; + if (fabs(rotation.z) > TRANSMITTER_MIN_RATE) { + _thrust += rotation.z * TRANSMITTER_LATERAL_FORCE_SCALE * deltaTime * right; + } + if (fabs(rotation.x) > TRANSMITTER_MIN_RATE) { + _thrust += -rotation.x * TRANSMITTER_FWD_FORCE_SCALE * deltaTime * front; + } + if (fabs(rotation.y) > TRANSMITTER_MIN_YAW_RATE) { + _bodyYawDelta += rotation.y * TRANSMITTER_YAW_SCALE * deltaTime; + } + if (transmitter->getTouchState()->state == 'D') { + _thrust += TRANSMITTER_UP_FORCE_SCALE * + (float)(transmitter->getTouchState()->y - TOUCH_POSITION_RANGE_HALF) / TOUCH_POSITION_RANGE_HALF * + TRANSMITTER_LIFT_SCALE * + deltaTime * + up; + } + } +} + void Avatar::simulate(float deltaTime, Transmitter* transmitter) { - //figure out if the mouse cursor is over any body spheres... - checkForMouseRayTouching(); + glm::quat orientation = getOrientation(); + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + + // Update movement timers + if (!_owningAgent) { + _elapsedTimeSinceCollision += deltaTime; + const float VELOCITY_MOVEMENT_TIMER_THRESHOLD = 0.2f; + if (glm::length(_velocity) < VELOCITY_MOVEMENT_TIMER_THRESHOLD) { + _elapsedTimeMoving = 0.f; + _elapsedTimeStopped += deltaTime; + } else { + _elapsedTimeStopped = 0.f; + _elapsedTimeMoving += deltaTime; + } + } + + // Collect thrust forces from keyboard and devices + if (!_owningAgent) { + updateThrust(deltaTime, transmitter); + } // copy velocity so we can use it later for acceleration glm::vec3 oldVelocity = getVelocity(); + if (!_owningAgent) { + // update position by velocity + _position += _velocity * deltaTime; + + // calculate speed + _speed = glm::length(_velocity); + } + + //figure out if the mouse cursor is over any body spheres... + if (!_owningAgent) { + checkForMouseRayTouching(); + } + // update balls if (_balls) { _balls->simulate(deltaTime); } @@ -385,12 +483,13 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { //update the movement of the hand and process handshaking with other avatars... updateHandMovementAndTouching(deltaTime); - _avatarTouch.simulate(deltaTime); // apply gravity and collision with the ground/floor if (!_owningAgent && USING_AVATAR_GRAVITY) { _velocity += _gravity * (GRAVITY_EARTH * deltaTime); + } + if (!_owningAgent) { updateCollisionWithEnvironment(); } @@ -407,65 +506,11 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { updateCollisionWithVoxels(); } - glm::quat orientation = getOrientation(); - glm::vec3 front = orientation * IDENTITY_FRONT; - glm::vec3 right = orientation * IDENTITY_RIGHT; - glm::vec3 up = orientation * IDENTITY_UP; - - // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) - const float THRUST_MAG_UP = 800.0f; - const float THRUST_MAG_DOWN = 200.f; - const float THRUST_MAG_FWD = 300.f; - const float THRUST_MAG_BACK = 150.f; - const float THRUST_MAG_LATERAL = 200.f; - const float THRUST_JUMP = 100.f; - if (!_owningAgent) { - - // Add Thrusts from keyboard - if (_driveKeys[FWD ]) {_thrust += THRUST_MAG_FWD * deltaTime * front;} - if (_driveKeys[BACK ]) {_thrust -= THRUST_MAG_BACK * deltaTime * front;} - if (_driveKeys[RIGHT ]) {_thrust += THRUST_MAG_LATERAL * deltaTime * right;} - if (_driveKeys[LEFT ]) {_thrust -= THRUST_MAG_LATERAL * deltaTime * right;} - if (_driveKeys[UP ]) {_thrust += THRUST_MAG_UP * deltaTime * up;} - if (_driveKeys[DOWN ]) {_thrust -= THRUST_MAG_DOWN * deltaTime * up;} - if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} - if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;} - - if (_shouldJump) { - _thrust += THRUST_JUMP * up; - _shouldJump = false; - } - // Add thrusts from Transmitter - if (transmitter) { - transmitter->checkForLostTransmitter(); - glm::vec3 rotation = transmitter->getEstimatedRotation(); - const float TRANSMITTER_MIN_RATE = 1.f; - const float TRANSMITTER_MIN_YAW_RATE = 4.f; - const float TRANSMITTER_LATERAL_FORCE_SCALE = 5.f; - const float TRANSMITTER_FWD_FORCE_SCALE = 25.f; - const float TRANSMITTER_UP_FORCE_SCALE = 100.f; - const float TRANSMITTER_YAW_SCALE = 10.0f; - const float TRANSMITTER_LIFT_SCALE = 3.f; - const float TOUCH_POSITION_RANGE_HALF = 32767.f; - if (fabs(rotation.z) > TRANSMITTER_MIN_RATE) { - _thrust += rotation.z * TRANSMITTER_LATERAL_FORCE_SCALE * deltaTime * right; - } - if (fabs(rotation.x) > TRANSMITTER_MIN_RATE) { - _thrust += -rotation.x * TRANSMITTER_FWD_FORCE_SCALE * deltaTime * front; - } - if (fabs(rotation.y) > TRANSMITTER_MIN_YAW_RATE) { - _bodyYawDelta += rotation.y * TRANSMITTER_YAW_SCALE * deltaTime; - } - if (transmitter->getTouchState()->state == 'D') { - _thrust += TRANSMITTER_UP_FORCE_SCALE * - (float)(transmitter->getTouchState()->y - TOUCH_POSITION_RANGE_HALF) / TOUCH_POSITION_RANGE_HALF * - TRANSMITTER_LIFT_SCALE * - deltaTime * - up; - } - } - + + // add thrust to velocity + _velocity += _thrust * deltaTime; + // update body yaw by body yaw delta orientation = orientation * glm::quat(glm::radians( glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime)); @@ -477,37 +522,22 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _bodyYawDelta *= bodySpinMomentum; _bodyRollDelta *= bodySpinMomentum; - // add thrust to velocity - _velocity += _thrust * deltaTime; - // Decay velocity. If velocity is really low, increase decay to simulate static friction - const float VELOCITY_DECAY_UNDER_THRUST = 0.0; - const float VELOCITY_FAST_DECAY = 0.8; - const float VELOCITY_SLOW_DECAY = 8.0; - const float VELOCITY_HALT_DECAY = 100.0; + const float VELOCITY_DECAY_UNDER_THRUST = 0.2; + const float VELOCITY_FAST_DECAY = 0.6; + const float VELOCITY_SLOW_DECAY = 3.0; const float VELOCITY_FAST_THRESHOLD = 2.0f; - const float VELOCITY_HALT_THRESHOLD = 0.15f; float decayConstant, decay; if (glm::length(_thrust) > 0.f) { decayConstant = VELOCITY_DECAY_UNDER_THRUST; } else if (glm::length(_velocity) > VELOCITY_FAST_THRESHOLD) { decayConstant = VELOCITY_FAST_DECAY; - } else if (glm::length(_velocity) > VELOCITY_HALT_THRESHOLD) { - decayConstant = VELOCITY_SLOW_DECAY; } else { - decayConstant = VELOCITY_HALT_DECAY; - } - + decayConstant = VELOCITY_SLOW_DECAY; + } decay = glm::clamp(1.0f - decayConstant * deltaTime, 0.0f, 1.0f); _velocity *= decay; - - - // update position by velocity - _position += _velocity * deltaTime; - - // calculate speed - _speed = glm::length(_velocity); - + //pitch and roll the body as a function of forward speed and turning delta const float BODY_PITCH_WHILE_WALKING = -20.0; const float BODY_ROLL_WHILE_TURNING = 0.2; @@ -527,13 +557,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { //the following will be used to make the avatar upright no matter what gravity is setOrientation(computeRotationFromBodyToWorldUp(tiltDecay) * orientation); - // If another avatar is near, dampen velocity as a function of closeness - if (_distanceToNearestAvatar < PERIPERSONAL_RADIUS) { - float closeness = 1.0f - (_distanceToNearestAvatar / PERIPERSONAL_RADIUS); - float avatarDrag = glm::clamp(1.0f - closeness * AVATAR_BRAKING_STRENGTH * deltaTime, 0.0f, 1.0f); - _velocity *= avatarDrag; - } - // Compute instantaneous acceleration float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime; const float ACCELERATION_PITCH_DECAY = 0.4f; @@ -798,36 +821,53 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d } void Avatar::updateCollisionWithEnvironment() { + glm::vec3 up = getBodyUpDirection(); float radius = _height * 0.125f; + const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; + const float ENVIRONMENT_SURFACE_DAMPING = 0.01; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { - applyCollisionWithScene(penetration); + applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); } } + void Avatar::updateCollisionWithVoxels() { float radius = _height * 0.125f; + const float VOXEL_ELASTICITY = 1.4f; + const float VOXEL_DAMPING = 0.0; glm::vec3 penetration; if (Application::getInstance()->getVoxels()->findCapsulePenetration( _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { - applyCollisionWithScene(penetration); + applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } -void Avatar::applyCollisionWithScene(const glm::vec3& penetration) { +void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { + // + // Update the avatar in response to a hard collision. Position will be reset exactly + // to outside the colliding surface. Velocity will be modified according to elasticity. + // + // if elasticity = 1.0, collision is inelastic. + // if elasticity > 1.0, collision is elastic. + // _position -= penetration; - static float KINETIC_FRICTION_DAMPING = 0.95f; - static float ELASTIC_COLLISION_FACTOR = 1.4f; // 1.0 = inelastic, > 2.0 = pinball bumper! + static float HALTING_VELOCITY = 0.2f; // cancel out the velocity component in the direction of penetration float penetrationLength = glm::length(penetration); if (penetrationLength > EPSILON) { + _elapsedTimeSinceCollision = 0.0f; glm::vec3 direction = penetration / penetrationLength; - _velocity -= glm::dot(_velocity, direction) * direction * ELASTIC_COLLISION_FACTOR; - _velocity *= KINETIC_FRICTION_DAMPING; + _velocity -= glm::dot(_velocity, direction) * direction * elasticity; + _velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f); + if ((glm::length(_velocity) < HALTING_VELOCITY) && (glm::length(_thrust) == 0.f)) { + // If moving really slowly after a collision, and not applying forces, stop altogether + _velocity *= 0.f; + } } } @@ -849,7 +889,6 @@ void Avatar::updateAvatarCollisions(float deltaTime) { // apply forces from collision applyCollisionWithOtherAvatar(otherAvatar, deltaTime); } - // test other avatar hand position for proximity glm::vec3 v(_skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position); v -= otherAvatar->getPosition(); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 5be04b06c3..db4f4dd7a6 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -85,6 +85,7 @@ public: void init(); void reset(); void simulate(float deltaTime, Transmitter* transmitter); + void updateThrust(float deltaTime, Transmitter * transmitter); void updateHeadFromGyros(float frametime, SerialInterface * serialInterface); void updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight); void addBodyYaw(float y) {_bodyYaw += y;}; @@ -118,6 +119,9 @@ public: float getHeight () const { return _height;} AvatarMode getMode () const { return _mode;} float getLeanScale () const { return _leanScale;} + float getElapsedTimeStopped () const { return _elapsedTimeStopped;} + float getElapsedTimeMoving () const { return _elapsedTimeMoving;} + float getElapsedTimeSinceCollision() const { return _elapsedTimeSinceCollision;} float getAbsoluteHeadYaw () const; float getAbsoluteHeadPitch () const; Head& getHead () {return _head; } @@ -195,13 +199,16 @@ private: float _height; Balls* _balls; AvatarTouch _avatarTouch; - float _distanceToNearestAvatar; // How close is the nearest avatar? + float _distanceToNearestAvatar; // How close is the nearest avatar? glm::vec3 _gravity; glm::vec3 _worldUpDirection; glm::vec3 _mouseRayOrigin; glm::vec3 _mouseRayDirection; Avatar* _interactingOther; bool _isMouseTurningRight; + float _elapsedTimeMoving; // Timers to drive camera transitions when moving + float _elapsedTimeStopped; + float _elapsedTimeSinceCollision; AvatarVoxelSystem _voxels; @@ -221,7 +228,7 @@ private: void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); void updateCollisionWithEnvironment(); void updateCollisionWithVoxels(); - void applyCollisionWithScene(const glm::vec3& penetration); + void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2); From d517487d1bc23a51ed16e17c4faeebc09047fd80 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 13 Jun 2013 11:35:36 -0700 Subject: [PATCH 60/71] OK I wanted us to jump just a bit higher. --- interface/src/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index c55f082be5..c89a078f23 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -353,7 +353,7 @@ void Avatar::updateThrust(float deltaTime, Transmitter * transmitter) { const float THRUST_MAG_FWD = 300.f; const float THRUST_MAG_BACK = 150.f; const float THRUST_MAG_LATERAL = 200.f; - const float THRUST_JUMP = 65.f; + const float THRUST_JUMP = 120.f; // Add Thrusts from keyboard if (_driveKeys[FWD ]) {_thrust += THRUST_MAG_FWD * deltaTime * front;} From b85f91a7d46a5dd0803ae2ed5b52622aa1b98e15 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 13 Jun 2013 12:05:06 -0700 Subject: [PATCH 61/71] fixes per code review --- interface/src/Application.cpp | 4 ++-- interface/src/Application.h | 4 ++-- interface/src/Avatar.cpp | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c5d913c65e..40f7de7e85 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1016,7 +1016,7 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { } } -const glm::vec3 Application::getMouseVoxelWorldCoordinates(VoxelDetail _mouseVoxel) { +const glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel) { return glm::vec3((_mouseVoxel.x + _mouseVoxel.s / 2.f) * TREE_SCALE, (_mouseVoxel.y + _mouseVoxel.s / 2.f) * TREE_SCALE, (_mouseVoxel.z + _mouseVoxel.s / 2.f) * TREE_SCALE); @@ -2206,7 +2206,7 @@ void Application::displayStats() { } } -void Application::renderThrustAtVoxel(glm::vec3 thrust) { +void Application::renderThrustAtVoxel(const glm::vec3& thrust) { if (_mousePressed) { glColor3f(1, 0, 0); glLineWidth(2.0f); diff --git a/interface/src/Application.h b/interface/src/Application.h index 655268024b..1d50b5065f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -67,7 +67,7 @@ public: void wheelEvent(QWheelEvent* event); - const glm::vec3 getMouseVoxelWorldCoordinates(VoxelDetail _mouseVoxel); + const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel); Avatar* getAvatar() { return &_myAvatar; } Camera* getCamera() { return &_myCamera; } @@ -95,7 +95,7 @@ private slots: void setRenderFirstPerson(bool firstPerson); - void renderThrustAtVoxel(glm::vec3 thrust); + void renderThrustAtVoxel(const glm::vec3& thrust); void renderLineToTouchedVoxel(); void setFrustumOffset(bool frustumOffset); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index c89a078f23..a2ff33ca52 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -617,7 +617,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { // set head lookat position if (!_owningAgent) { - //if (_camera) if (_interactingOther) { _head.setLookAtPosition(_interactingOther->calculateAverageEyePosition()); } else { From b57a78c414f76d6c877e362b66645a2696bedceb Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Jun 2013 13:15:08 -0700 Subject: [PATCH 62/71] Another fix: using strlen to determine the length of the packet is... unwise. Remember the length when we create it. This should fix the voxel server's not appearing. --- libraries/shared/src/AgentList.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index e1b4bd9d63..7a4803586e 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -205,6 +205,7 @@ void AgentList::sendDomainServerCheckIn() { // construct the DS check in packet if we need to static unsigned char* checkInPacket = NULL; + static int checkInPacketSize; if (!checkInPacket) { int numBytesAgentsOfInterest = _agentTypesOfInterest ? strlen((char*) _agentTypesOfInterest) : 0; @@ -236,10 +237,10 @@ void AgentList::sendDomainServerCheckIn() { packetPosition += numBytesAgentsOfInterest; } - *packetPosition = '\0'; + checkInPacketSize = packetPosition - checkInPacket; } - _agentSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, strlen((char*) checkInPacket)); + _agentSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, checkInPacketSize); } int AgentList::processDomainServerList(unsigned char *packetData, size_t dataBytes) { From e32f9f387a21298f733cab3ea4c74c817c8c4bba Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 13 Jun 2013 13:50:56 -0700 Subject: [PATCH 63/71] Basic random eye movements added, and fixation on camera in mirror mode. --- interface/src/Application.cpp | 7 +++++- interface/src/Avatar.cpp | 3 ++- interface/src/Head.cpp | 42 +++++++++++++---------------------- interface/src/Head.h | 2 ++ interface/src/Util.cpp | 5 +++++ interface/src/Util.h | 2 ++ 6 files changed, 32 insertions(+), 29 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 40f7de7e85..1faec3fb51 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2042,7 +2042,12 @@ void Application::displaySide(Camera& whichCamera) { } agentList->unlock(); - // Render my own Avatar + // Render my own Avatar + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + _myAvatar.getHead().setLookAtPosition(_myCamera.getPosition()); + } else { + _myAvatar.getHead().setLookAtPosition(glm::vec3(0.0f, 0.0f, 0.0f)); + } _myAvatar.render(_lookingInMirror->isChecked(), _renderAvatarBalls->isChecked()); _myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked()); } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index a2ff33ca52..0a1ff22ce6 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -616,13 +616,14 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } // set head lookat position + /* if (!_owningAgent) { if (_interactingOther) { _head.setLookAtPosition(_interactingOther->calculateAverageEyePosition()); } else { _head.setLookAtPosition(glm::vec3(0.0f, 0.0f, 0.0f)); // 0,0,0 represents NOT looking at anything } - } + }*/ _head.setBodyRotation (glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); _head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position); diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index c7fac99d8b..a3bf63293a 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -67,7 +67,9 @@ Head::Head(Avatar* owningAvatar) : _lookingInMirror(false), _renderLookatVectors(false), _mohawkTriangleFan(NULL), - _mohawkColors(NULL) + _mohawkColors(NULL), + _saccade(0.0f, 0.0f, 0.0f), + _saccadeTarget(0.0f, 0.0f, 0.0f) { if (USING_PHYSICAL_MOHAWK) { resetHairPhysics(); @@ -102,32 +104,19 @@ void Head::resetHairPhysics() { void Head::simulate(float deltaTime, bool isMine) { - - const float HEAD_MOTION_DECAY = 0.00; - /* - // Decay head back to center if turned on - if (isMine && _returnHeadToCenter) { + // Update eye saccades + const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f; + const float AVERAGE_SACCADE_INTERVAL = 4.0f; + const float MICROSACCADE_MAGNITUDE = 0.002f; + const float SACCADE_MAGNITUDE = 0.04; - // Decay rotation back toward center - _pitch *= (1.0f - HEAD_MOTION_DECAY * _returnSpringScale * deltaTime); - _yaw *= (1.0f - HEAD_MOTION_DECAY * _returnSpringScale * deltaTime); - _roll *= (1.0f - HEAD_MOTION_DECAY * _returnSpringScale * deltaTime); + if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) { + _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector(); + } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) { + _saccadeTarget = SACCADE_MAGNITUDE * randVector(); } - - // For invensense gyro, decay only slightly when near center (until we add fusion) - if (isMine) { - const float RETURN_RANGE = 15.0; - const float RETURN_STRENGTH = 0.5; - if (fabs(_pitch) < RETURN_RANGE) { _pitch *= (1.0f - RETURN_STRENGTH * deltaTime); } - if (fabs(_yaw ) < RETURN_RANGE) { _yaw *= (1.0f - RETURN_STRENGTH * deltaTime); } - if (fabs(_roll ) < RETURN_RANGE) { _roll *= (1.0f - RETURN_STRENGTH * deltaTime); } - } - */ - - // decay lean - _leanForward *= (1.f - HEAD_MOTION_DECAY * 30 * deltaTime); - _leanSideways *= (1.f - HEAD_MOTION_DECAY * 30 * deltaTime); + _saccade += (_saccadeTarget - _saccade) * 0.50f; // Update audio trailing average for rendering facial animations const float AUDIO_AVERAGING_SECS = 0.05; @@ -504,8 +493,7 @@ void Head::renderEyeBalls() { if (_lookingAtSomething) { //rotate the eyeball to aim towards the lookat position - glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - _leftEyePosition); // the lookat direction - glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); + glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _leftEyePosition); glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP); glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z); glRotatef(180.0, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations @@ -548,7 +536,7 @@ void Head::renderEyeBalls() { if (_lookingAtSomething) { //rotate the eyeball to aim towards the lookat position - glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - _rightEyePosition); + glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _rightEyePosition); glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP); glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z); diff --git a/interface/src/Head.h b/interface/src/Head.h index d331b98efc..6f492a6d1d 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -103,6 +103,8 @@ private: HairTuft _hairTuft[NUM_HAIR_TUFTS]; glm::vec3* _mohawkTriangleFan; glm::vec3* _mohawkColors; + glm::vec3 _saccade; + glm::vec3 _saccadeTarget; // private methods void createMohawk(); diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index cc566dd6fb..93596e1c1d 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -267,6 +267,11 @@ double diffclock(timeval *clock1,timeval *clock2) return diffms; } +// Return a random vector of average length 1 +const glm::vec3 randVector() { + return glm::vec3(randFloat() - 0.5f, randFloat() - 0.5f, randFloat() - 0.5f) * 2.f; +} + static TextRenderer* textRenderer(int mono) { static TextRenderer* monoRenderer = new TextRenderer(MONO_FONT_FAMILY); static TextRenderer* proportionalRenderer = new TextRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT); diff --git a/interface/src/Util.h b/interface/src/Util.h index 6cac785956..24cbad9e68 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -32,6 +32,8 @@ float azimuth_to(glm::vec3 head_pos, glm::vec3 source_pos); float angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float head_yaw); float randFloat(); +const glm::vec3 randVector(); + void render_world_box(); int widthText(float scale, int mono, char const* string); float widthChar(float scale, int mono, char ch); From 687966c48648221e2618a7ba8f467e564349954f Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 13 Jun 2013 14:04:51 -0700 Subject: [PATCH 64/71] Other people's avatar's look where they are mousing --- interface/src/Application.cpp | 8 +++++--- interface/src/Avatar.cpp | 10 ---------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1faec3fb51..f2ee4fcff1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1449,6 +1449,10 @@ void Application::update(float deltaTime) { // tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); + + // Set where I am looking based on my mouse ray (so that other people can see) + glm::vec3 myLookAtFromMouse(mouseRayOrigin - mouseRayDirection); + _myAvatar.getHead().setLookAtPosition(myLookAtFromMouse); // If we are dragging on a voxel, add thrust according to the amount the mouse is dragging const float VOXEL_GRAB_THRUST = 5.0f; @@ -2045,9 +2049,7 @@ void Application::displaySide(Camera& whichCamera) { // Render my own Avatar if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myAvatar.getHead().setLookAtPosition(_myCamera.getPosition()); - } else { - _myAvatar.getHead().setLookAtPosition(glm::vec3(0.0f, 0.0f, 0.0f)); - } + } _myAvatar.render(_lookingInMirror->isChecked(), _renderAvatarBalls->isChecked()); _myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked()); } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 0a1ff22ce6..a3618b1726 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -615,16 +615,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } } - // set head lookat position - /* - if (!_owningAgent) { - if (_interactingOther) { - _head.setLookAtPosition(_interactingOther->calculateAverageEyePosition()); - } else { - _head.setLookAtPosition(glm::vec3(0.0f, 0.0f, 0.0f)); // 0,0,0 represents NOT looking at anything - } - }*/ - _head.setBodyRotation (glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); _head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position); _head.setScale (_bodyBall[ BODY_BALL_HEAD_BASE ].radius); From 8af0da754f704e8ea6f46e77f793d981328ab3b7 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 13 Jun 2013 14:21:14 -0700 Subject: [PATCH 65/71] we are always looking at something --- interface/src/Head.cpp | 28 +++++----------------------- interface/src/Head.h | 2 -- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index a3bf63293a..e2b9fdb3ad 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -57,7 +57,6 @@ Head::Head(Avatar* owningAvatar) : _mouthPosition(0.0f, 0.0f, 0.0f), _scale(1.0f), _browAudioLift(0.0f), - _lookingAtSomething(false), _gravity(0.0f, -1.0f, 0.0f), _lastLoudness(0.0f), _averageLoudness(0.0f), @@ -137,30 +136,13 @@ void Head::simulate(float deltaTime, bool isMine) { _browAudioLift *= 0.7f; - // based on the nature of the lookat position, determine if the eyes can look / are looking at it. - determineIfLookingAtSomething(); - + // based on the nature of the lookat position, determine if the eyes can look / are looking at it. if (USING_PHYSICAL_MOHAWK) { updateHairPhysics(deltaTime); } } -void Head::determineIfLookingAtSomething() { - - if ( fabs(_lookAtPosition.x + _lookAtPosition.y + _lookAtPosition.z) == 0.0 ) { // a lookatPosition of 0,0,0 signifies NOT looking - _lookingAtSomething = false; - } else { - glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - calculateAverageEyePosition()); - float dot = glm::dot(targetLookatAxis, getFrontDirection()); - if (dot < MINIMUM_EYE_ROTATION_DOT) { // too far off from center for the eyes to rotate - _lookingAtSomething = false; - } else { - _lookingAtSomething = true; - } - } -} - void Head::calculateGeometry() { //generate orientation directions glm::quat orientation = getOrientation(); @@ -207,9 +189,9 @@ void Head::render(bool lookingInMirror, float alpha) { renderEyeBalls(); renderEars(); renderMouth(); - renderEyeBrows(); + renderEyeBrows(); - if (_renderLookatVectors && _lookingAtSomething) { + if (_renderLookatVectors) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); } } @@ -490,7 +472,7 @@ void Head::renderEyeBalls() { glPushMatrix(); - if (_lookingAtSomething) { + if (1) { //rotate the eyeball to aim towards the lookat position glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _leftEyePosition); glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); @@ -533,7 +515,7 @@ void Head::renderEyeBalls() { glPushMatrix(); - if (_lookingAtSomething) { + if (1) { //rotate the eyeball to aim towards the lookat position glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _rightEyePosition); diff --git a/interface/src/Head.h b/interface/src/Head.h index 6f492a6d1d..a46571a99d 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -91,7 +91,6 @@ private: glm::vec3 _mouthPosition; float _scale; float _browAudioLift; - bool _lookingAtSomething; glm::vec3 _gravity; float _lastLoudness; float _averageLoudness; @@ -115,7 +114,6 @@ private: void renderMouth(); void renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition); void calculateGeometry(); - void determineIfLookingAtSomething(); void resetHairPhysics(); void updateHairPhysics(float deltaTime); }; From 1556886a647256d2d02288614faf0b8501dc4a2e Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 13 Jun 2013 14:33:09 -0700 Subject: [PATCH 66/71] fixing reversed lookat, rendering for all avatars --- interface/src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f2ee4fcff1..c23901da79 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1451,7 +1451,7 @@ void Application::update(float deltaTime) { _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); // Set where I am looking based on my mouse ray (so that other people can see) - glm::vec3 myLookAtFromMouse(mouseRayOrigin - mouseRayDirection); + glm::vec3 myLookAtFromMouse(mouseRayOrigin + mouseRayDirection); _myAvatar.getHead().setLookAtPosition(myLookAtFromMouse); // If we are dragging on a voxel, add thrust according to the amount the mouse is dragging @@ -2042,6 +2042,7 @@ void Application::displaySide(Camera& whichCamera) { avatar->init(); } avatar->render(false, _renderAvatarBalls->isChecked()); + avatar->setDisplayingLookatVectors(_renderLookatOn->isChecked()); } } agentList->unlock(); From 466c062bc1ada71ffaa35db102e0bad0fb76ab59 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Jun 2013 14:41:06 -0700 Subject: [PATCH 67/71] Use a bound texture for the iris, load it with Qt rather than lodepng (we can probably just remove the lodepng dependency). --- interface/src/Avatar.cpp | 1 + interface/src/Head.cpp | 36 +++++++++++++++++++++--------------- interface/src/Head.h | 3 +++ 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index a2ff33ca52..4d1eca808d 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -271,6 +271,7 @@ Avatar::~Avatar() { } void Avatar::init() { + _head.init(); _voxels.init(); _initialized = true; } diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index c7fac99d8b..b8f89fbde6 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -5,6 +5,9 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include + +#include + #include "Application.h" #include "Avatar.h" #include "Head.h" @@ -36,9 +39,7 @@ const float IRIS_RADIUS = 0.007; const float IRIS_PROTRUSION = 0.0145f; const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png"; -unsigned int IRIS_TEXTURE_WIDTH = 768; -unsigned int IRIS_TEXTURE_HEIGHT = 498; -vector irisTexture; +GLuint Head::_irisTextureID = 0; Head::Head(Avatar* owningAvatar) : HeadData((AvatarData*)owningAvatar), @@ -74,6 +75,19 @@ Head::Head(Avatar* owningAvatar) : } } +void Head::init() { + if (_irisTextureID == 0) { + switchToResourcesParentIfRequired(); + QImage image = QImage(IRIS_TEXTURE_FILENAME).convertToFormat(QImage::Format_RGB888); + + glGenTextures(1, &_irisTextureID); + glBindTexture(GL_TEXTURE_2D, _irisTextureID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, image.constBits()); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + void Head::reset() { _yaw = _pitch = _roll = 0.0f; _leanForward = _leanSideways = 0.0f; @@ -469,22 +483,12 @@ void Head::renderEyeBrows() { void Head::renderEyeBalls() { - if (::irisTexture.size() == 0) { - switchToResourcesParentIfRequired(); - unsigned error = lodepng::decode(::irisTexture, IRIS_TEXTURE_WIDTH, IRIS_TEXTURE_HEIGHT, IRIS_TEXTURE_FILENAME); - if (error != 0) { - printLog("error %u: %s\n", error, lodepng_error_text(error)); - } - } - // setup the texutre to be used on each iris GLUquadric* irisQuadric = gluNewQuadric(); gluQuadricTexture(irisQuadric, GL_TRUE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gluQuadricOrientation(irisQuadric, GLU_OUTSIDE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IRIS_TEXTURE_WIDTH, IRIS_TEXTURE_HEIGHT, - 0, GL_RGBA, GL_UNSIGNED_BYTE, &::irisTexture[0]); + glBindTexture(GL_TEXTURE_2D, _irisTextureID); // render white ball of left eyeball glPushMatrix(); @@ -579,6 +583,8 @@ void Head::renderEyeBalls() { // delete the iris quadric now that we're done with it gluDeleteQuadric(irisQuadric); glPopMatrix(); + + glBindTexture(GL_TEXTURE_2D, 0); } void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) { diff --git a/interface/src/Head.h b/interface/src/Head.h index d331b98efc..2deb638eff 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -31,6 +31,7 @@ class Head : public HeadData { public: Head(Avatar* owningAvatar); + void init(); void reset(); void simulate(float deltaTime, bool isMine); void render(bool lookingInMirror, float alpha); @@ -104,6 +105,8 @@ private: glm::vec3* _mohawkTriangleFan; glm::vec3* _mohawkColors; + static GLuint _irisTextureID; + // private methods void createMohawk(); void renderHeadSphere(); From f6e6ceddfe957a7c2ce4db6155b7f04d9deecff9 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 13 Jun 2013 14:53:10 -0700 Subject: [PATCH 68/71] Head camera scaling always one if gyros off so that mouse look works. --- interface/src/Application.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c23901da79..4ed6d270c0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -303,6 +303,8 @@ void Application::paintGL() { glEnable(GL_LINE_SMOOTH); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + float headCameraScale = _serialHeadSensor.active ? _headCameraPitchYawScale : 1.0f; + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness (100.0f); _myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition()); @@ -318,11 +320,11 @@ void Application::paintGL() { } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTightness(0.0f); // In first person, camera follows head exactly without delay _myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition()); - _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(_headCameraPitchYawScale)); + _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(headCameraScale)); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition()); - _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(_headCameraPitchYawScale)); + _myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(headCameraScale)); } // Update camera position From e401663459e9f49d57fa66917b1b5cbd386f6732 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Jun 2013 15:58:49 -0700 Subject: [PATCH 69/71] Added per-pixel specular highlight to irises. --- interface/resources/shaders/iris.frag | 21 ++++++++++++ interface/resources/shaders/iris.vert | 20 +++++++++++ interface/src/Head.cpp | 49 ++++++++++++++++----------- interface/src/Head.h | 2 ++ 4 files changed, 72 insertions(+), 20 deletions(-) create mode 100644 interface/resources/shaders/iris.frag create mode 100644 interface/resources/shaders/iris.vert diff --git a/interface/resources/shaders/iris.frag b/interface/resources/shaders/iris.frag new file mode 100644 index 0000000000..2f5b06d6c6 --- /dev/null +++ b/interface/resources/shaders/iris.frag @@ -0,0 +1,21 @@ +#version 120 + +// +// iris.frag +// fragment shader +// +// Created by Andrzej Kapolka on 6/13/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +// the iris texture +uniform sampler2D texture; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), normalize(normal))); + gl_FragColor = vec4(gl_Color.rgb * texture2D(texture, gl_TexCoord[0].st).rgb + + pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 1.0); +} diff --git a/interface/resources/shaders/iris.vert b/interface/resources/shaders/iris.vert new file mode 100644 index 0000000000..83602f3e99 --- /dev/null +++ b/interface/resources/shaders/iris.vert @@ -0,0 +1,20 @@ +#version 120 + +// +// iris.vert +// vertex shader +// +// Created by Andrzej Kapolka on 6/13/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +// the interpolated normal +varying vec4 normal; + +void main(void) { + normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); + gl_FrontColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient + + gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = ftransform(); +} diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index b8f89fbde6..bba9269b73 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -8,13 +8,13 @@ #include +#include + #include "Application.h" #include "Avatar.h" #include "Head.h" #include "Util.h" -#include -#include -#include +#include "renderer/ProgramObject.h" using namespace std; @@ -39,7 +39,8 @@ const float IRIS_RADIUS = 0.007; const float IRIS_PROTRUSION = 0.0145f; const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png"; -GLuint Head::_irisTextureID = 0; +ProgramObject* Head::_irisProgram = 0; +GLuint Head::_irisTextureID; Head::Head(Avatar* owningAvatar) : HeadData((AvatarData*)owningAvatar), @@ -76,8 +77,15 @@ Head::Head(Avatar* owningAvatar) : } void Head::init() { - if (_irisTextureID == 0) { + if (_irisProgram == 0) { switchToResourcesParentIfRequired(); + _irisProgram = new ProgramObject(); + _irisProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/iris.vert"); + _irisProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/iris.frag"); + _irisProgram->link(); + + _irisProgram->setUniformValue("texture", 0); + QImage image = QImage(IRIS_TEXTURE_FILENAME).convertToFormat(QImage::Format_RGB888); glGenTextures(1, &_irisTextureID); @@ -483,12 +491,11 @@ void Head::renderEyeBrows() { void Head::renderEyeBalls() { - // setup the texutre to be used on each iris + // setup the texture to be used on each iris GLUquadric* irisQuadric = gluNewQuadric(); gluQuadricTexture(irisQuadric, GL_TRUE); gluQuadricOrientation(irisQuadric, GLU_OUTSIDE); - glBindTexture(GL_TEXTURE_2D, _irisTextureID); // render white ball of left eyeball glPushMatrix(); @@ -497,6 +504,17 @@ void Head::renderEyeBalls() { gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30); glPopMatrix(); + //render white ball of right eyeball + glPushMatrix(); + glColor3fv(EYEBALL_COLOR); + glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); + gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30); + glPopMatrix(); + + _irisProgram->bind(); + glBindTexture(GL_TEXTURE_2D, _irisTextureID); + glEnable(GL_TEXTURE_2D); + glm::vec3 front = getFrontDirection(); // render left iris @@ -529,20 +547,11 @@ void Head::renderEyeBalls() { glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f);//push the iris out a bit (otherwise - inside of eyeball!) glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris - glEnable(GL_TEXTURE_2D); gluSphere(irisQuadric, IRIS_RADIUS, 15, 15); - glDisable(GL_TEXTURE_2D); glPopMatrix(); } glPopMatrix(); - //render white ball of right eyeball - glPushMatrix(); - glColor3fv(EYEBALL_COLOR); - glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); - gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30); - glPopMatrix(); - // render right iris glPushMatrix(); { glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); //translate to eyeball position @@ -574,17 +583,17 @@ void Head::renderEyeBalls() { glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f);//push the iris out a bit (otherwise - inside of eyeball!) glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris - glEnable(GL_TEXTURE_2D); gluSphere(irisQuadric, IRIS_RADIUS, 15, 15); - glDisable(GL_TEXTURE_2D); glPopMatrix(); } + _irisProgram->release(); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + // delete the iris quadric now that we're done with it gluDeleteQuadric(irisQuadric); glPopMatrix(); - - glBindTexture(GL_TEXTURE_2D, 0); } void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) { diff --git a/interface/src/Head.h b/interface/src/Head.h index 2deb638eff..6d0f7819e4 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -26,6 +26,7 @@ enum eyeContactTargets const int NUM_HAIR_TUFTS = 4; class Avatar; +class ProgramObject; class Head : public HeadData { public: @@ -105,6 +106,7 @@ private: glm::vec3* _mohawkTriangleFan; glm::vec3* _mohawkColors; + static ProgramObject* _irisProgram; static GLuint _irisTextureID; // private methods From dd1df47c71262da6653546a8f9888df248c519e4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 13 Jun 2013 16:20:28 -0700 Subject: [PATCH 70/71] fixes per review --- interface/src/Head.cpp | 67 ++++++++++-------------------------------- 1 file changed, 16 insertions(+), 51 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 790b88ef6e..63fc6d6c25 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -491,32 +491,15 @@ void Head::renderEyeBalls() { // render left iris glPushMatrix(); { glTranslatef(_leftEyePosition.x, _leftEyePosition.y, _leftEyePosition.z); //translate to eyeball position - glPushMatrix(); - - if (1) { - - //rotate the eyeball to aim towards the lookat position - glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _leftEyePosition); glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); - float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP); - glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z); - glRotatef(180.0, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations - } else { - - //rotate the eyeball to aim straight ahead - glm::vec3 rotationAxisToHeadFront = glm::cross(front, IDENTITY_UP); - float angleToHeadFront = 180.0f - angleBetween(front, IDENTITY_UP); - glRotatef(angleToHeadFront, rotationAxisToHeadFront.x, rotationAxisToHeadFront.y, rotationAxisToHeadFront.z); - - //set the amount of roll (for correction after previous rotations) - float rollRotation = angleBetween(front, IDENTITY_FRONT); - float dot = glm::dot(front, -IDENTITY_RIGHT); - if ( dot < 0.0f ) { rollRotation = -rollRotation; } - glRotatef(rollRotation, 0.0f, 1.0f, 0.0f); //roll the iris or correct roll about the lookat vector - } - - glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f);//push the iris out a bit (otherwise - inside of eyeball!) - glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris + //rotate the eyeball to aim towards the lookat position + glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _leftEyePosition); + glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); + float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP); + glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z); + glRotatef(180.0, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations + glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f); + glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris gluSphere(irisQuadric, IRIS_RADIUS, 15, 15); glPopMatrix(); } @@ -525,34 +508,16 @@ void Head::renderEyeBalls() { // render right iris glPushMatrix(); { glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); //translate to eyeball position - glPushMatrix(); - - if (1) { - - //rotate the eyeball to aim towards the lookat position - glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _rightEyePosition); - glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); - float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP); - glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z); - glRotatef(180.0f, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations - } else { - - //rotate the eyeball to aim straight ahead - glm::vec3 rotationAxisToHeadFront = glm::cross(front, IDENTITY_UP); - float angleToHeadFront = 180.0f - angleBetween(front, IDENTITY_UP); - glRotatef(angleToHeadFront, rotationAxisToHeadFront.x, rotationAxisToHeadFront.y, rotationAxisToHeadFront.z); - - //set the amount of roll (for correction after previous rotations) - float rollRotation = angleBetween(front, IDENTITY_FRONT); - float dot = glm::dot(front, -IDENTITY_RIGHT); - if ( dot < 0.0f ) { rollRotation = -rollRotation; } - glRotatef(rollRotation, 0.0f, 1.0f, 0.0f); //roll the iris or correct roll about the lookat vector - } - - glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f);//push the iris out a bit (otherwise - inside of eyeball!) - glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris + //rotate the eyeball to aim towards the lookat position + glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _rightEyePosition); + glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); + float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP); + glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z); + glRotatef(180.0f, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations + glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f); + glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris gluSphere(irisQuadric, IRIS_RADIUS, 15, 15); glPopMatrix(); } From 0f897340ee7f45d192cf88132b83a0c069cb38ab Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 13 Jun 2013 16:42:31 -0700 Subject: [PATCH 71/71] New iris texture from Ryan. --- interface/resources/images/iris.png | Bin 147484 -> 156181 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/interface/resources/images/iris.png b/interface/resources/images/iris.png index fce68fe95d116df97d7e099d755f9035a7229744..3c5b605e3d44e5d862fe213d0579bd6566f24549 100644 GIT binary patch literal 156181 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 #4I5vhb>H%C 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

f(1I5C8#WD9s=$`DxAh8S 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ξb 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 bHiGGdA*%}X&I|zo0YP3`MXFB1B<%kIy=bp&