mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 01:36:56 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into localmode
This commit is contained in:
commit
985b8d66d2
40 changed files with 919 additions and 619 deletions
|
@ -59,7 +59,7 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
|
||||||
printf("sending packet of size=%d\n",sizeOut);
|
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;
|
delete[] bufferOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,7 @@ static void renderMovingBug() {
|
||||||
if (::shouldShowPacketsPerSecond) {
|
if (::shouldShowPacketsPerSecond) {
|
||||||
printf("sending packet of size=%d\n", sizeOut);
|
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;
|
delete[] bufferOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,13 +238,12 @@ static void renderMovingBug() {
|
||||||
if (::shouldShowPacketsPerSecond) {
|
if (::shouldShowPacketsPerSecond) {
|
||||||
printf("sending packet of size=%d\n", sizeOut);
|
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;
|
delete[] bufferOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float intensity = 0.5f;
|
float intensity = 0.5f;
|
||||||
float intensityIncrement = 0.1f;
|
float intensityIncrement = 0.1f;
|
||||||
const float MAX_INTENSITY = 1.0f;
|
const float MAX_INTENSITY = 1.0f;
|
||||||
|
@ -345,7 +344,7 @@ static void sendBlinkingStringOfLights() {
|
||||||
if (::shouldShowPacketsPerSecond) {
|
if (::shouldShowPacketsPerSecond) {
|
||||||
printf("sending packet of size=%d\n",sizeOut);
|
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;
|
delete[] bufferOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +386,7 @@ static void sendBlinkingStringOfLights() {
|
||||||
if (::shouldShowPacketsPerSecond) {
|
if (::shouldShowPacketsPerSecond) {
|
||||||
printf("sending packet of size=%d\n",sizeOut);
|
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;
|
delete[] bufferOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -510,7 +509,7 @@ void sendDanceFloor() {
|
||||||
if (::shouldShowPacketsPerSecond) {
|
if (::shouldShowPacketsPerSecond) {
|
||||||
printf("sending packet of size=%d\n", sizeOut);
|
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;
|
delete[] bufferOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -607,7 +606,7 @@ static void sendBillboard() {
|
||||||
if (::shouldShowPacketsPerSecond) {
|
if (::shouldShowPacketsPerSecond) {
|
||||||
printf("sending packet of size=%d\n", sizeOut);
|
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;
|
delete[] bufferOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -644,14 +643,14 @@ void* animateVoxels(void* args) {
|
||||||
sendDanceFloor();
|
sendDanceFloor();
|
||||||
}
|
}
|
||||||
|
|
||||||
double end = usecTimestampNow();
|
long long end = usecTimestampNow();
|
||||||
double elapsedSeconds = (end - ::start) / 1000000.0;
|
long long elapsedSeconds = (end - ::start) / 1000000;
|
||||||
if (::shouldShowPacketsPerSecond) {
|
if (::shouldShowPacketsPerSecond) {
|
||||||
printf("packetsSent=%ld, bytesSent=%ld pps=%f bps=%f\n",packetsSent,bytesSent,
|
printf("packetsSent=%ld, bytesSent=%ld pps=%f bps=%f\n",packetsSent,bytesSent,
|
||||||
(float)(packetsSent/elapsedSeconds),(float)(bytesSent/elapsedSeconds));
|
(float)(packetsSent/elapsedSeconds),(float)(bytesSent/elapsedSeconds));
|
||||||
}
|
}
|
||||||
// dynamically sleep until we need to fire off the next set of voxels
|
// 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) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
|
@ -702,7 +701,6 @@ int main(int argc, const char * argv[])
|
||||||
|
|
||||||
agentList->linkedDataCreateCallback = NULL; // do we need a callback?
|
agentList->linkedDataCreateCallback = NULL; // do we need a callback?
|
||||||
agentList->startSilentAgentRemovalThread();
|
agentList->startSilentAgentRemovalThread();
|
||||||
agentList->startDomainServerCheckInThread();
|
|
||||||
|
|
||||||
srand((unsigned)time(0));
|
srand((unsigned)time(0));
|
||||||
|
|
||||||
|
@ -713,16 +711,21 @@ int main(int argc, const char * argv[])
|
||||||
|
|
||||||
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||||
ssize_t receivedBytes;
|
ssize_t receivedBytes;
|
||||||
|
|
||||||
|
timeval lastDomainServerCheckIn = {};
|
||||||
|
AgentList::getInstance()->setAgentTypesOfInterest(&AGENT_TYPE_VOXEL_SERVER, 1);
|
||||||
|
|
||||||
// loop to send to agents requesting data
|
// loop to send to agents requesting data
|
||||||
while (true) {
|
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)) {
|
if (agentList->getAgentSocket()->receive(&agentPublicAddress, packetData, &receivedBytes)) {
|
||||||
switch (packetData[0]) {
|
AgentList::getInstance()->processAgentData(&agentPublicAddress, packetData, receivedBytes);
|
||||||
default: {
|
|
||||||
AgentList::getInstance()->processAgentData(&agentPublicAddress, packetData, receivedBytes);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,6 @@ int main(int argc, const char* argv[]) {
|
||||||
agentList->linkedDataCreateCallback = attachNewBufferToAgent;
|
agentList->linkedDataCreateCallback = attachNewBufferToAgent;
|
||||||
|
|
||||||
agentList->startSilentAgentRemovalThread();
|
agentList->startSilentAgentRemovalThread();
|
||||||
agentList->startDomainServerCheckInThread();
|
|
||||||
|
|
||||||
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||||
|
|
||||||
|
@ -114,7 +113,16 @@ int main(int argc, const char* argv[]) {
|
||||||
|
|
||||||
gettimeofday(&startTime, NULL);
|
gettimeofday(&startTime, NULL);
|
||||||
|
|
||||||
|
timeval lastDomainServerCheckIn = {};
|
||||||
|
|
||||||
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();
|
||||||
|
}
|
||||||
|
|
||||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||||
PositionalAudioRingBuffer* positionalRingBuffer = (PositionalAudioRingBuffer*) agent->getLinkedData();
|
PositionalAudioRingBuffer* positionalRingBuffer = (PositionalAudioRingBuffer*) agent->getLinkedData();
|
||||||
|
|
||||||
|
@ -325,7 +333,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) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
|
|
|
@ -66,7 +66,6 @@ int main(int argc, const char* argv[]) {
|
||||||
|
|
||||||
agentList->linkedDataCreateCallback = attachAvatarDataToAgent;
|
agentList->linkedDataCreateCallback = attachAvatarDataToAgent;
|
||||||
|
|
||||||
agentList->startDomainServerCheckInThread();
|
|
||||||
agentList->startSilentAgentRemovalThread();
|
agentList->startSilentAgentRemovalThread();
|
||||||
|
|
||||||
sockaddr *agentAddress = new sockaddr;
|
sockaddr *agentAddress = new sockaddr;
|
||||||
|
@ -80,8 +79,19 @@ int main(int argc, const char* argv[]) {
|
||||||
|
|
||||||
uint16_t agentID = 0;
|
uint16_t agentID = 0;
|
||||||
Agent* avatarAgent = NULL;
|
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) {
|
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)) {
|
if (agentList->getAgentSocket()->receive(agentAddress, packetData, &receivedBytes)) {
|
||||||
switch (packetData[0]) {
|
switch (packetData[0]) {
|
||||||
case PACKET_HEADER_HEAD_DATA:
|
case PACKET_HEADER_HEAD_DATA:
|
||||||
|
@ -129,7 +139,6 @@ int main(int argc, const char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
agentList->stopSilentAgentRemovalThread();
|
agentList->stopSilentAgentRemovalThread();
|
||||||
agentList->stopDomainServerCheckInThread();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,15 +94,14 @@ int main(int argc, const char * argv[])
|
||||||
|
|
||||||
agentList->startSilentAgentRemovalThread();
|
agentList->startSilentAgentRemovalThread();
|
||||||
|
|
||||||
uint16_t packetAgentID = 0;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (agentList->getAgentSocket()->receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes) &&
|
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<char, Agent *> newestSoloAgents;
|
std::map<char, Agent *> newestSoloAgents;
|
||||||
|
|
||||||
agentType = packetData[1];
|
agentType = packetData[1];
|
||||||
unpackSocket(packetData + 2, (sockaddr*) &agentLocalAddress);
|
int numBytesSocket = unpackSocket(packetData + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE),
|
||||||
|
(sockaddr*) &agentLocalAddress);
|
||||||
|
|
||||||
// check the agent public address
|
// check the agent public address
|
||||||
// if it matches our local address we're on the same box
|
// if it matches our local address we're on the same box
|
||||||
|
@ -124,51 +123,59 @@ int main(int argc, const char * argv[])
|
||||||
agentList->increaseAgentID();
|
agentList->increaseAgentID();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentBufferPos = broadcastPacket + 1;
|
currentBufferPos = broadcastPacket + sizeof(PACKET_HEADER);
|
||||||
startPointer = currentBufferPos;
|
startPointer = currentBufferPos;
|
||||||
|
|
||||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
unsigned char* agentTypesOfInterest = packetData + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE)
|
||||||
if (!agent->matches((sockaddr*) &agentPublicAddress, (sockaddr*) &agentLocalAddress, agentType)) {
|
+ numBytesSocket + sizeof(unsigned char);
|
||||||
if (memchr(SOLO_AGENT_TYPES, agent->getType(), sizeof(SOLO_AGENT_TYPES)) == NULL) {
|
int numInterestTypes = *(agentTypesOfInterest - 1);
|
||||||
// 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 (numInterestTypes > 0) {
|
||||||
if (agentType != AGENT_TYPE_AVATAR || agent->getType() != AGENT_TYPE_AVATAR) {
|
// if the agent has sent no types of interest, assume they want nothing but their own ID back
|
||||||
currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, &(*agent));
|
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 (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 {
|
} else {
|
||||||
// solo agent, we need to only send newest
|
// solo agent, we need to only send newest
|
||||||
if (newestSoloAgents[agent->getType()] == NULL ||
|
if (newestSoloAgents[agent->getType()] == NULL ||
|
||||||
newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) {
|
newestSoloAgents[agent->getType()]->getWakeMicrostamp() < agent->getWakeMicrostamp()) {
|
||||||
// we have to set the newer solo agent to add it to the broadcast later
|
// we have to set the newer solo agent to add it to the broadcast later
|
||||||
newestSoloAgents[agent->getType()] = &(*agent);
|
newestSoloAgents[agent->getType()] = &(*agent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
double timeNow = usecTimestampNow();
|
|
||||||
|
for (std::map<char, Agent *>::iterator soloAgent = newestSoloAgents.begin();
|
||||||
// this is the agent, just update last receive to now
|
soloAgent != newestSoloAgents.end();
|
||||||
agent->setLastHeardMicrostamp(timeNow);
|
soloAgent++) {
|
||||||
|
// this is the newest alive solo agent, add them to the packet
|
||||||
// grab the ID for this agent so we can send it back with the packet
|
currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, soloAgent->second);
|
||||||
packetAgentID = agent->getAgentID();
|
|
||||||
|
|
||||||
if (packetData[0] == PACKET_HEADER_DOMAIN_RFD
|
|
||||||
&& memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) {
|
|
||||||
agent->setWakeMicrostamp(timeNow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update last receive to now
|
||||||
|
long long timeNow = usecTimestampNow();
|
||||||
|
newAgent->setLastHeardMicrostamp(timeNow);
|
||||||
|
|
||||||
for (std::map<char, Agent *>::iterator soloAgent = newestSoloAgents.begin();
|
if (packetData[0] == PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY
|
||||||
soloAgent != newestSoloAgents.end();
|
&& memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) {
|
||||||
soloAgent++) {
|
newAgent->setWakeMicrostamp(timeNow);
|
||||||
// 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
|
// 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
|
// send the constructed list back to this agent
|
||||||
agentList->getAgentSocket()->send((sockaddr*) &agentPublicAddress,
|
agentList->getAgentSocket()->send((sockaddr*) &agentPublicAddress,
|
||||||
|
|
|
@ -82,9 +82,6 @@ int main(int argc, const char* argv[]) {
|
||||||
// create an AgentList instance to handle communication with other agents
|
// create an AgentList instance to handle communication with other agents
|
||||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LISTEN_PORT);
|
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
|
// start the agent list thread that will kill off agents when they stop talking
|
||||||
agentList->startSilentAgentRemovalThread();
|
agentList->startSilentAgentRemovalThread();
|
||||||
|
|
||||||
|
@ -131,11 +128,23 @@ int main(int argc, const char* argv[]) {
|
||||||
broadcastPacket[0] = PACKET_HEADER_HEAD_DATA;
|
broadcastPacket[0] = PACKET_HEADER_HEAD_DATA;
|
||||||
|
|
||||||
timeval thisSend;
|
timeval thisSend;
|
||||||
double numMicrosecondsSleep = 0;
|
long long numMicrosecondsSleep = 0;
|
||||||
|
|
||||||
int handStateTimer = 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) {
|
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
|
// update the thisSend timeval to the current time
|
||||||
gettimeofday(&thisSend, NULL);
|
gettimeofday(&thisSend, NULL);
|
||||||
|
|
||||||
|
@ -201,7 +210,6 @@ int main(int argc, const char* argv[]) {
|
||||||
pthread_join(receiveAgentDataThread, NULL);
|
pthread_join(receiveAgentDataThread, NULL);
|
||||||
|
|
||||||
// stop the agent list's threads
|
// stop the agent list's threads
|
||||||
agentList->stopDomainServerCheckInThread();
|
|
||||||
agentList->stopPingUnknownAgentsThread();
|
agentList->stopPingUnknownAgentsThread();
|
||||||
agentList->stopSilentAgentRemovalThread();
|
agentList->stopSilentAgentRemovalThread();
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,9 +167,6 @@ int main(int argc, char* argv[]) {
|
||||||
pthread_t receiveAgentDataThread;
|
pthread_t receiveAgentDataThread;
|
||||||
pthread_create(&receiveAgentDataThread, NULL, receiveAgentData, NULL);
|
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
|
// start the agent list thread that will kill off agents when they stop talking
|
||||||
agentList->startSilentAgentRemovalThread();
|
agentList->startSilentAgentRemovalThread();
|
||||||
|
|
||||||
|
@ -190,9 +187,22 @@ int main(int argc, char* argv[]) {
|
||||||
unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO;
|
unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO;
|
||||||
|
|
||||||
timeval thisSend;
|
timeval thisSend;
|
||||||
double numMicrosecondsSleep = 0;
|
long long 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) {
|
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) {
|
if (::triggerDistance) {
|
||||||
|
|
||||||
// update the thisSend timeval to the current time
|
// update the thisSend timeval to the current time
|
||||||
|
@ -260,7 +270,6 @@ int main(int argc, char* argv[]) {
|
||||||
pthread_join(receiveAgentDataThread, NULL);
|
pthread_join(receiveAgentDataThread, NULL);
|
||||||
|
|
||||||
// stop the agent list's threads
|
// stop the agent list's threads
|
||||||
agentList->stopDomainServerCheckInThread();
|
|
||||||
agentList->stopSilentAgentRemovalThread();
|
agentList->stopSilentAgentRemovalThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 152 KiB |
21
interface/resources/shaders/iris.frag
Normal file
21
interface/resources/shaders/iris.frag
Normal file
|
@ -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);
|
||||||
|
}
|
20
interface/resources/shaders/iris.vert
Normal file
20
interface/resources/shaders/iris.vert
Normal file
|
@ -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();
|
||||||
|
}
|
|
@ -62,8 +62,6 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
const bool TESTING_AVATAR_TOUCH = false;
|
|
||||||
|
|
||||||
// Starfield information
|
// Starfield information
|
||||||
static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
|
static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
|
||||||
static char STAR_CACHE_FILE[] = "cachedStars.txt";
|
static char STAR_CACHE_FILE[] = "cachedStars.txt";
|
||||||
|
@ -144,7 +142,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_viewFrustumOffsetDistance(25.0),
|
_viewFrustumOffsetDistance(25.0),
|
||||||
_viewFrustumOffsetUp(0.0),
|
_viewFrustumOffsetUp(0.0),
|
||||||
_audioScope(256, 200, true),
|
_audioScope(256, 200, true),
|
||||||
_manualFirstPerson(false),
|
|
||||||
_mouseX(0),
|
_mouseX(0),
|
||||||
_mouseY(0),
|
_mouseY(0),
|
||||||
_mousePressed(false),
|
_mousePressed(false),
|
||||||
|
@ -170,7 +167,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_window->setWindowTitle("Interface");
|
_window->setWindowTitle("Interface");
|
||||||
printLog("Interface Startup:\n");
|
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<const char**>(argv);
|
const char** constArgv = const_cast<const char**>(argv);
|
||||||
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
|
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
|
||||||
if (portStr) {
|
if (portStr) {
|
||||||
|
@ -207,10 +204,13 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
WSADATA WsaData;
|
WSADATA WsaData;
|
||||||
int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData);
|
int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// tell the AgentList instance who to tell the domain server we care about
|
||||||
|
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
|
// start the agentList threads
|
||||||
AgentList::getInstance()->startSilentAgentRemovalThread();
|
AgentList::getInstance()->startSilentAgentRemovalThread();
|
||||||
AgentList::getInstance()->startDomainServerCheckInThread();
|
|
||||||
AgentList::getInstance()->startPingUnknownAgentsThread();
|
AgentList::getInstance()->startPingUnknownAgentsThread();
|
||||||
|
|
||||||
_window->setCentralWidget(_glWidget);
|
_window->setCentralWidget(_glWidget);
|
||||||
|
@ -303,9 +303,11 @@ void Application::paintGL() {
|
||||||
glEnable(GL_LINE_SMOOTH);
|
glEnable(GL_LINE_SMOOTH);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
float headCameraScale = _serialHeadSensor.active ? _headCameraPitchYawScale : 1.0f;
|
||||||
|
|
||||||
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||||
_myCamera.setTightness (100.0f);
|
_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)));
|
_myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||||
|
|
||||||
} else if (OculusManager::isConnected()) {
|
} else if (OculusManager::isConnected()) {
|
||||||
|
@ -317,12 +319,12 @@ void Application::paintGL() {
|
||||||
|
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
} else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||||
_myCamera.setTightness(0.0f); // In first person, camera follows head exactly without delay
|
_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));
|
_myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(headCameraScale));
|
||||||
|
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||||
_myCamera.setTargetPosition(_myAvatar.getHeadJointPosition());
|
_myCamera.setTargetPosition(_myAvatar.getUprightHeadPosition());
|
||||||
_myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(_headCameraPitchYawScale));
|
_myCamera.setTargetRotation(_myAvatar.getHead().getCameraOrientation(headCameraScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update camera position
|
// Update camera position
|
||||||
|
@ -424,7 +426,7 @@ static void sendVoxelServerAddScene() {
|
||||||
char message[100];
|
char message[100];
|
||||||
sprintf(message,"%c%s",'Z',"add scene");
|
sprintf(message,"%c%s",'Z',"add scene");
|
||||||
int messageSize = strlen(message) + 1;
|
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) {
|
void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
|
@ -508,6 +510,9 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Qt::Key_E:
|
case Qt::Key_E:
|
||||||
|
if (!_myAvatar.getDriveKeys(UP)) {
|
||||||
|
_myAvatar.jump();
|
||||||
|
}
|
||||||
_myAvatar.setDriveKeys(UP, 1);
|
_myAvatar.setDriveKeys(UP, 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -718,6 +723,9 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
_mouseX = event->x();
|
_mouseX = event->x();
|
||||||
_mouseY = event->y();
|
_mouseY = event->y();
|
||||||
|
_mouseDragStartedX = _mouseX;
|
||||||
|
_mouseDragStartedY = _mouseY;
|
||||||
|
_mouseVoxelDragging = _mouseVoxel;
|
||||||
_mousePressed = true;
|
_mousePressed = true;
|
||||||
maybeEditVoxelUnderCursor();
|
maybeEditVoxelUnderCursor();
|
||||||
|
|
||||||
|
@ -767,6 +775,9 @@ void Application::timer() {
|
||||||
if (!_serialHeadSensor.active) {
|
if (!_serialHeadSensor.active) {
|
||||||
_serialHeadSensor.pair();
|
_serialHeadSensor.pair();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ask the agent list to check in with the domain server
|
||||||
|
AgentList::getInstance()->sendDomainServerCheckIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
static glm::vec3 getFaceVector(BoxFace face) {
|
static glm::vec3 getFaceVector(BoxFace face) {
|
||||||
|
@ -821,6 +832,7 @@ void Application::terminate() {
|
||||||
|
|
||||||
static void sendAvatarVoxelURLMessage(const QUrl& url) {
|
static void sendAvatarVoxelURLMessage(const QUrl& url) {
|
||||||
uint16_t ownerID = AgentList::getInstance()->getOwnerID();
|
uint16_t ownerID = AgentList::getInstance()->getOwnerID();
|
||||||
|
|
||||||
if (ownerID == UNKNOWN_AGENT_ID) {
|
if (ownerID == UNKNOWN_AGENT_ID) {
|
||||||
return; // we don't yet know who we are
|
return; // we don't yet know who we are
|
||||||
}
|
}
|
||||||
|
@ -874,6 +886,10 @@ void Application::editPreferences() {
|
||||||
headCameraPitchYawScale->setValue(_headCameraPitchYawScale);
|
headCameraPitchYawScale->setValue(_headCameraPitchYawScale);
|
||||||
form->addRow("Head Camera Pitch/Yaw Scale:", 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);
|
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||||
dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject()));
|
dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject()));
|
||||||
|
@ -887,6 +903,7 @@ void Application::editPreferences() {
|
||||||
sendAvatarVoxelURLMessage(url);
|
sendAvatarVoxelURLMessage(url);
|
||||||
|
|
||||||
_headCameraPitchYawScale = headCameraPitchYawScale->value();
|
_headCameraPitchYawScale = headCameraPitchYawScale->value();
|
||||||
|
_myAvatar.setLeanScale(leanScale->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::pair() {
|
void Application::pair() {
|
||||||
|
@ -897,6 +914,8 @@ void Application::setHead(bool head) {
|
||||||
if (head) {
|
if (head) {
|
||||||
_myCamera.setMode(CAMERA_MODE_MIRROR);
|
_myCamera.setMode(CAMERA_MODE_MIRROR);
|
||||||
_myCamera.setModeShiftRate(100.0f);
|
_myCamera.setModeShiftRate(100.0f);
|
||||||
|
_manualFirstPerson->setChecked(false);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
||||||
_myCamera.setModeShiftRate(1.0f);
|
_myCamera.setModeShiftRate(1.0f);
|
||||||
|
@ -914,7 +933,9 @@ void Application::setFullscreen(bool fullscreen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setRenderFirstPerson(bool firstPerson) {
|
void Application::setRenderFirstPerson(bool firstPerson) {
|
||||||
_manualFirstPerson = firstPerson;
|
if (firstPerson && _lookingInMirror->isChecked()) {
|
||||||
|
_lookingInMirror->trigger();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setFrustumOffset(bool frustumOffset) {
|
void Application::setFrustumOffset(bool frustumOffset) {
|
||||||
|
@ -992,11 +1013,17 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
|
||||||
int sizeOut;
|
int sizeOut;
|
||||||
|
|
||||||
if (createVoxelEditMessage(header, 0, 1, &detail, bufferOut, 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;
|
delete[] bufferOut;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
void Application::decreaseVoxelSize() {
|
void Application::decreaseVoxelSize() {
|
||||||
_mouseVoxelScale /= 2;
|
_mouseVoxelScale /= 2;
|
||||||
}
|
}
|
||||||
|
@ -1061,7 +1088,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 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) {
|
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
|
args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1125,7 +1152,7 @@ void Application::importVoxels() {
|
||||||
|
|
||||||
// If we have voxels left in the packet, then send the packet
|
// 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))) {
|
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) {
|
if (calculatedOctCode) {
|
||||||
|
@ -1177,7 +1204,7 @@ void Application::pasteVoxels() {
|
||||||
|
|
||||||
// If we have voxels left in the packet, then send the packet
|
// 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))) {
|
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) {
|
if (calculatedOctCode) {
|
||||||
|
@ -1206,7 +1233,7 @@ void Application::initMenu() {
|
||||||
(_gyroLook = optionsMenu->addAction("Gyro Look"))->setCheckable(true);
|
(_gyroLook = optionsMenu->addAction("Gyro Look"))->setCheckable(true);
|
||||||
_gyroLook->setChecked(false);
|
_gyroLook->setChecked(false);
|
||||||
(_mouseLook = optionsMenu->addAction("Mouse Look"))->setCheckable(true);
|
(_mouseLook = optionsMenu->addAction("Mouse Look"))->setCheckable(true);
|
||||||
_mouseLook->setChecked(false);
|
_mouseLook->setChecked(true);
|
||||||
(_showHeadMouse = optionsMenu->addAction("Head Mouse"))->setCheckable(true);
|
(_showHeadMouse = optionsMenu->addAction("Head Mouse"))->setCheckable(true);
|
||||||
_showHeadMouse->setChecked(false);
|
_showHeadMouse->setChecked(false);
|
||||||
(_transmitterDrives = optionsMenu->addAction("Transmitter Drive"))->setCheckable(true);
|
(_transmitterDrives = optionsMenu->addAction("Transmitter Drive"))->setCheckable(true);
|
||||||
|
@ -1230,7 +1257,6 @@ void Application::initMenu() {
|
||||||
_renderAtmosphereOn->setShortcut(Qt::SHIFT | Qt::Key_A);
|
_renderAtmosphereOn->setShortcut(Qt::SHIFT | Qt::Key_A);
|
||||||
(_renderGroundPlaneOn = renderMenu->addAction("Ground Plane"))->setCheckable(true);
|
(_renderGroundPlaneOn = renderMenu->addAction("Ground Plane"))->setCheckable(true);
|
||||||
_renderGroundPlaneOn->setChecked(true);
|
_renderGroundPlaneOn->setChecked(true);
|
||||||
_renderGroundPlaneOn->setShortcut(Qt::SHIFT | Qt::Key_G);
|
|
||||||
(_renderAvatarsOn = renderMenu->addAction("Avatars"))->setCheckable(true);
|
(_renderAvatarsOn = renderMenu->addAction("Avatars"))->setCheckable(true);
|
||||||
_renderAvatarsOn->setChecked(true);
|
_renderAvatarsOn->setChecked(true);
|
||||||
(_renderAvatarBalls = renderMenu->addAction("Avatar as Balls"))->setCheckable(true);
|
(_renderAvatarBalls = renderMenu->addAction("Avatar as Balls"))->setCheckable(true);
|
||||||
|
@ -1239,8 +1265,8 @@ void Application::initMenu() {
|
||||||
_renderFrameTimerOn->setChecked(false);
|
_renderFrameTimerOn->setChecked(false);
|
||||||
(_renderLookatOn = renderMenu->addAction("Lookat Vectors"))->setCheckable(true);
|
(_renderLookatOn = renderMenu->addAction("Lookat Vectors"))->setCheckable(true);
|
||||||
_renderLookatOn->setChecked(false);
|
_renderLookatOn->setChecked(false);
|
||||||
|
(_manualFirstPerson = renderMenu->addAction(
|
||||||
renderMenu->addAction("First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P)->setCheckable(true);
|
"First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P))->setCheckable(true);
|
||||||
|
|
||||||
QMenu* toolsMenu = menuBar->addMenu("Tools");
|
QMenu* toolsMenu = menuBar->addMenu("Tools");
|
||||||
(_renderStatsOn = toolsMenu->addAction("Stats"))->setCheckable(true);
|
(_renderStatsOn = toolsMenu->addAction("Stats"))->setCheckable(true);
|
||||||
|
@ -1425,7 +1451,31 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
// tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position
|
// tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position
|
||||||
_myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection);
|
_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;
|
||||||
|
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 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;
|
||||||
|
_voxelThrust += lateralToVoxel * VOXEL_GRAB_THRUST * deltaTime * mouseDrag.x;
|
||||||
|
|
||||||
|
// Add thrust from voxel grabbing to the avatar
|
||||||
|
_myAvatar.addThrust(_voxelThrust);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
_mouseVoxel.s = 0.0f;
|
_mouseVoxel.s = 0.0f;
|
||||||
if (checkedVoxelModeAction() != 0 &&
|
if (checkedVoxelModeAction() != 0 &&
|
||||||
(fabs(_myAvatar.getVelocity().x) +
|
(fabs(_myAvatar.getVelocity().x) +
|
||||||
|
@ -1554,30 +1604,27 @@ void Application::update(float deltaTime) {
|
||||||
_myAvatar.simulate(deltaTime, NULL);
|
_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 (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) {
|
||||||
if (_manualFirstPerson) {
|
if (_manualFirstPerson->isChecked()) {
|
||||||
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) {
|
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) {
|
||||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||||
_myCamera.setModeShiftRate(1.0f);
|
_myCamera.setModeShiftRate(1.0f);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_myAvatar.getIsNearInteractingOther()) {
|
const float THIRD_PERSON_SHIFT_VELOCITY = 2.0f;
|
||||||
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) {
|
const float TIME_BEFORE_SHIFT_INTO_FIRST_PERSON = 0.75f;
|
||||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
const float TIME_BEFORE_SHIFT_INTO_THIRD_PERSON = 0.1f;
|
||||||
_myCamera.setModeShiftRate(1.0f);
|
|
||||||
}
|
if ((_myAvatar.getElapsedTimeStopped() > TIME_BEFORE_SHIFT_INTO_FIRST_PERSON)
|
||||||
} else {
|
&& (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON)) {
|
||||||
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
|
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||||
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
|
_myCamera.setModeShiftRate(1.0f);
|
||||||
_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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1664,7 +1711,7 @@ void Application::updateAvatar(float deltaTime) {
|
||||||
|
|
||||||
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
|
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));
|
AgentList::getInstance()->broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, broadcastReceivers, sizeof(broadcastReceivers));
|
||||||
|
|
||||||
// once in a while, send my voxel url
|
// once in a while, send my voxel url
|
||||||
|
@ -1945,6 +1992,10 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
// Enable to show line from me to the voxel I am touching
|
||||||
|
//renderLineToTouchedVoxel();
|
||||||
|
//renderThrustAtVoxel(_voxelThrust);
|
||||||
|
|
||||||
// draw a red sphere
|
// draw a red sphere
|
||||||
float sphereRadius = 0.25f;
|
float sphereRadius = 0.25f;
|
||||||
glColor3f(1,0,0);
|
glColor3f(1,0,0);
|
||||||
|
@ -1993,11 +2044,15 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
avatar->init();
|
avatar->init();
|
||||||
}
|
}
|
||||||
avatar->render(false, _renderAvatarBalls->isChecked());
|
avatar->render(false, _renderAvatarBalls->isChecked());
|
||||||
|
avatar->setDisplayingLookatVectors(_renderLookatOn->isChecked());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
agentList->unlock();
|
agentList->unlock();
|
||||||
|
|
||||||
// Render my own Avatar
|
// Render my own Avatar
|
||||||
|
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||||
|
_myAvatar.getHead().setLookAtPosition(_myCamera.getPosition());
|
||||||
|
}
|
||||||
_myAvatar.render(_lookingInMirror->isChecked(), _renderAvatarBalls->isChecked());
|
_myAvatar.render(_lookingInMirror->isChecked(), _renderAvatarBalls->isChecked());
|
||||||
_myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked());
|
_myAvatar.setDisplayingLookatVectors(_renderLookatOn->isChecked());
|
||||||
}
|
}
|
||||||
|
@ -2063,9 +2118,8 @@ void Application::displayOverlay() {
|
||||||
// Show on-screen msec timer
|
// Show on-screen msec timer
|
||||||
if (_renderFrameTimerOn->isChecked()) {
|
if (_renderFrameTimerOn->isChecked()) {
|
||||||
char frameTimer[10];
|
char frameTimer[10];
|
||||||
double mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
|
long long mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
|
||||||
mSecsNow = mSecsNow - floor(mSecsNow / 1000.0) * 1000.0;
|
sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000));
|
||||||
sprintf(frameTimer, "%3.0f\n", mSecsNow);
|
|
||||||
drawtext(_glWidget->width() - 100, _glWidget->height() - 20, 0.30, 0, 1.0, 0, frameTimer, 0, 0, 0);
|
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);
|
drawtext(_glWidget->width() - 102, _glWidget->height() - 22, 0.30, 0, 1.0, 0, frameTimer, 1, 1, 1);
|
||||||
}
|
}
|
||||||
|
@ -2161,6 +2215,32 @@ void Application::displayStats() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::renderThrustAtVoxel(const 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()
|
// renderViewFrustum()
|
||||||
//
|
//
|
||||||
|
@ -2437,6 +2517,8 @@ void Application::resetSensors() {
|
||||||
QCursor::setPos(_headMouseX, _headMouseY);
|
QCursor::setPos(_headMouseX, _headMouseY);
|
||||||
_myAvatar.reset();
|
_myAvatar.reset();
|
||||||
_myTransmitter.resetLevels();
|
_myTransmitter.resetLevels();
|
||||||
|
_myAvatar.setVelocity(glm::vec3(0,0,0));
|
||||||
|
_myAvatar.setThrust(glm::vec3(0,0,0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setShortcutsEnabled(QWidget* widget, bool enabled) {
|
static void setShortcutsEnabled(QWidget* widget, bool enabled) {
|
||||||
|
|
|
@ -67,6 +67,8 @@ public:
|
||||||
|
|
||||||
void wheelEvent(QWheelEvent* event);
|
void wheelEvent(QWheelEvent* event);
|
||||||
|
|
||||||
|
const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel);
|
||||||
|
|
||||||
Avatar* getAvatar() { return &_myAvatar; }
|
Avatar* getAvatar() { return &_myAvatar; }
|
||||||
Camera* getCamera() { return &_myCamera; }
|
Camera* getCamera() { return &_myCamera; }
|
||||||
ViewFrustum* getViewFrustum() { return &_viewFrustum; }
|
ViewFrustum* getViewFrustum() { return &_viewFrustum; }
|
||||||
|
@ -93,6 +95,9 @@ private slots:
|
||||||
|
|
||||||
void setRenderFirstPerson(bool firstPerson);
|
void setRenderFirstPerson(bool firstPerson);
|
||||||
|
|
||||||
|
void renderThrustAtVoxel(const glm::vec3& thrust);
|
||||||
|
void renderLineToTouchedVoxel();
|
||||||
|
|
||||||
void setFrustumOffset(bool frustumOffset);
|
void setFrustumOffset(bool frustumOffset);
|
||||||
void cycleFrustumRenderMode();
|
void cycleFrustumRenderMode();
|
||||||
|
|
||||||
|
@ -141,7 +146,7 @@ private:
|
||||||
void displayStats();
|
void displayStats();
|
||||||
|
|
||||||
void renderViewFrustum(ViewFrustum& viewFrustum);
|
void renderViewFrustum(ViewFrustum& viewFrustum);
|
||||||
|
|
||||||
void setupPaintingVoxel();
|
void setupPaintingVoxel();
|
||||||
void shiftPaintingColor();
|
void shiftPaintingColor();
|
||||||
void maybeEditVoxelUnderCursor();
|
void maybeEditVoxelUnderCursor();
|
||||||
|
@ -186,6 +191,7 @@ private:
|
||||||
QAction* _renderStatsOn; // Whether to show onscreen text overlay with stats
|
QAction* _renderStatsOn; // Whether to show onscreen text overlay with stats
|
||||||
QAction* _renderFrameTimerOn; // 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* _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
|
QAction* _logOn; // Whether to show on-screen log
|
||||||
QActionGroup* _voxelModeActions; // The group of voxel edit mode actions
|
QActionGroup* _voxelModeActions; // The group of voxel edit mode actions
|
||||||
QAction* _addVoxelMode; // Whether add voxel mode is enabled
|
QAction* _addVoxelMode; // Whether add voxel mode is enabled
|
||||||
|
@ -249,14 +255,18 @@ private:
|
||||||
Environment _environment;
|
Environment _environment;
|
||||||
|
|
||||||
int _headMouseX, _headMouseY;
|
int _headMouseX, _headMouseY;
|
||||||
bool _manualFirstPerson;
|
|
||||||
float _headCameraPitchYawScale;
|
float _headCameraPitchYawScale;
|
||||||
|
|
||||||
HandControl _handControl;
|
HandControl _handControl;
|
||||||
|
|
||||||
int _mouseX;
|
int _mouseX;
|
||||||
int _mouseY;
|
int _mouseY;
|
||||||
|
int _mouseDragStartedX;
|
||||||
|
int _mouseDragStartedY;
|
||||||
|
VoxelDetail _mouseVoxelDragging;
|
||||||
|
glm::vec3 _voxelThrust;
|
||||||
bool _mousePressed; // true if mouse has been pressed (clear when finished)
|
bool _mousePressed; // true if mouse has been pressed (clear when finished)
|
||||||
|
|
||||||
|
|
||||||
VoxelDetail _mouseVoxel; // details of the voxel under the mouse cursor
|
VoxelDetail _mouseVoxel; // details of the voxel under the mouse cursor
|
||||||
float _mouseVoxelScale; // the scale for adding/removing voxels
|
float _mouseVoxelScale; // the scale for adding/removing voxels
|
||||||
|
|
|
@ -74,12 +74,13 @@ Avatar::Avatar(Agent* owningAgent) :
|
||||||
_bodyRollDelta(0.0f),
|
_bodyRollDelta(0.0f),
|
||||||
_movedHandOffset(0.0f, 0.0f, 0.0f),
|
_movedHandOffset(0.0f, 0.0f, 0.0f),
|
||||||
_mode(AVATAR_MODE_STANDING),
|
_mode(AVATAR_MODE_STANDING),
|
||||||
_cameraPosition(0.0f, 0.0f, 0.0f),
|
|
||||||
_handHoldingPosition(0.0f, 0.0f, 0.0f),
|
_handHoldingPosition(0.0f, 0.0f, 0.0f),
|
||||||
_velocity(0.0f, 0.0f, 0.0f),
|
_velocity(0.0f, 0.0f, 0.0f),
|
||||||
_thrust(0.0f, 0.0f, 0.0f),
|
_thrust(0.0f, 0.0f, 0.0f),
|
||||||
|
_shouldJump(false),
|
||||||
_speed(0.0f),
|
_speed(0.0f),
|
||||||
_maxArmLength(0.0f),
|
_maxArmLength(0.0f),
|
||||||
|
_leanScale(0.5f),
|
||||||
_pelvisStandingHeight(0.0f),
|
_pelvisStandingHeight(0.0f),
|
||||||
_pelvisFloatingHeight(0.0f),
|
_pelvisFloatingHeight(0.0f),
|
||||||
_distanceToNearestAvatar(std::numeric_limits<float>::max()),
|
_distanceToNearestAvatar(std::numeric_limits<float>::max()),
|
||||||
|
@ -89,6 +90,9 @@ Avatar::Avatar(Agent* owningAgent) :
|
||||||
_mouseRayDirection(0.0f, 0.0f, 0.0f),
|
_mouseRayDirection(0.0f, 0.0f, 0.0f),
|
||||||
_interactingOther(NULL),
|
_interactingOther(NULL),
|
||||||
_isMouseTurningRight(false),
|
_isMouseTurningRight(false),
|
||||||
|
_elapsedTimeMoving(0.0f),
|
||||||
|
_elapsedTimeStopped(0.0f),
|
||||||
|
_elapsedTimeSinceCollision(0.0f),
|
||||||
_voxels(this)
|
_voxels(this)
|
||||||
{
|
{
|
||||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||||
|
@ -103,9 +107,11 @@ Avatar::Avatar(Agent* owningAgent) :
|
||||||
initializeBodyBalls();
|
initializeBodyBalls();
|
||||||
|
|
||||||
_height = _skeleton.getHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius + _bodyBall[ BODY_BALL_HEAD_BASE ].radius;
|
_height = _skeleton.getHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius + _bodyBall[ BODY_BALL_HEAD_BASE ].radius;
|
||||||
|
|
||||||
_maxArmLength = _skeleton.getArmLength();
|
_maxArmLength = _skeleton.getArmLength();
|
||||||
_pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius;
|
_pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius;
|
||||||
_pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius;
|
_pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius;
|
||||||
|
_pelvisToHeadLength = _skeleton.getPelvisToHeadLength();
|
||||||
|
|
||||||
_avatarTouch.setReachableRadius(PERIPERSONAL_RADIUS);
|
_avatarTouch.setReachableRadius(PERIPERSONAL_RADIUS);
|
||||||
|
|
||||||
|
@ -265,6 +271,7 @@ Avatar::~Avatar() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::init() {
|
void Avatar::init() {
|
||||||
|
_head.init();
|
||||||
_voxels.init();
|
_voxels.init();
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
@ -284,19 +291,12 @@ void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterfa
|
||||||
_head.setYaw(estimatedRotation.y * AMPLIFY_YAW);
|
_head.setYaw(estimatedRotation.y * AMPLIFY_YAW);
|
||||||
_head.setRoll(estimatedRotation.z * AMPLIFY_ROLL);
|
_head.setRoll(estimatedRotation.z * AMPLIFY_ROLL);
|
||||||
|
|
||||||
// Update head lean distance based on accelerometer data
|
// Update torso lean distance based on accelerometer data
|
||||||
glm::vec3 headRotationRates(_head.getPitch(), _head.getYaw(), _head.getRoll());
|
glm::vec3 estimatedPosition = serialInterface->getEstimatedPosition() * _leanScale;
|
||||||
|
const float TORSO_LENGTH = 0.5f;
|
||||||
glm::vec3 leaning = (serialInterface->getLastAcceleration() - serialInterface->getGravity())
|
const float MAX_LEAN = 45.0f;
|
||||||
* LEAN_SENSITIVITY
|
_head.setLeanSideways(glm::clamp(glm::degrees(atanf(-estimatedPosition.x / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN));
|
||||||
* (1.f - fminf(glm::length(headRotationRates), HEAD_RATE_MAX) / HEAD_RATE_MAX);
|
_head.setLeanForward(glm::clamp(glm::degrees(atanf(estimatedPosition.z / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Avatar::getAbsoluteHeadYaw() const {
|
float Avatar::getAbsoluteHeadYaw() const {
|
||||||
|
@ -315,45 +315,141 @@ glm::quat Avatar::getWorldAlignedOrientation () const {
|
||||||
return computeRotationFromBodyToWorldUp() * getOrientation();
|
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) {
|
void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) {
|
||||||
// Update head yaw and pitch based on mouse input
|
// Update head yaw and pitch based on mouse input
|
||||||
const float MOUSE_MOVE_RADIUS = 0.3f;
|
const float MOUSE_ROTATE_SPEED = 0.01f;
|
||||||
const float MOUSE_ROTATE_SPEED = 4.0f;
|
const float MOUSE_PITCH_SPEED = 0.02f;
|
||||||
const float MOUSE_PITCH_SPEED = 2.0f;
|
|
||||||
const int TITLE_BAR_HEIGHT = 46;
|
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)) {
|
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
|
// 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) {
|
int pixelMoveThreshold = screenWidth / 6;
|
||||||
_head.addPitch(-(mouseLocationY - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_PITCH_SPEED);
|
glm::vec2 mouseVector(mouseX - (screenWidth / 2), mouseY - (screenHeight / 2));
|
||||||
} else if (mouseLocationY < -MOUSE_MOVE_RADIUS) {
|
if (glm::length(mouseVector) > pixelMoveThreshold) {
|
||||||
_head.addPitch(-(mouseLocationY + MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_PITCH_SPEED);
|
mouseVector -= glm::normalize(mouseVector) * (float) pixelMoveThreshold;
|
||||||
|
_head.addYaw(-mouseVector.x * MOUSE_ROTATE_SPEED);
|
||||||
|
_head.addPitch(-mouseVector.y * MOUSE_PITCH_SPEED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = 120.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) {
|
void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
|
|
||||||
//figure out if the mouse cursor is over any body spheres...
|
glm::quat orientation = getOrientation();
|
||||||
checkForMouseRayTouching();
|
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
|
// copy velocity so we can use it later for acceleration
|
||||||
glm::vec3 oldVelocity = getVelocity();
|
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
|
// update balls
|
||||||
if (_balls) { _balls->simulate(deltaTime); }
|
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
|
// update avatar skeleton
|
||||||
_skeleton.update(deltaTime, getOrientation(), _position);
|
_skeleton.update(deltaTime, getOrientation(), _position);
|
||||||
|
|
||||||
|
@ -388,12 +484,13 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
|
|
||||||
//update the movement of the hand and process handshaking with other avatars...
|
//update the movement of the hand and process handshaking with other avatars...
|
||||||
updateHandMovementAndTouching(deltaTime);
|
updateHandMovementAndTouching(deltaTime);
|
||||||
|
|
||||||
_avatarTouch.simulate(deltaTime);
|
_avatarTouch.simulate(deltaTime);
|
||||||
|
|
||||||
// apply gravity and collision with the ground/floor
|
// apply gravity and collision with the ground/floor
|
||||||
if (!_owningAgent && USING_AVATAR_GRAVITY) {
|
if (!_owningAgent && USING_AVATAR_GRAVITY) {
|
||||||
_velocity += _gravity * (GRAVITY_EARTH * deltaTime);
|
_velocity += _gravity * (GRAVITY_EARTH * deltaTime);
|
||||||
|
}
|
||||||
|
if (!_owningAgent) {
|
||||||
updateCollisionWithEnvironment();
|
updateCollisionWithEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,57 +507,11 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
updateCollisionWithVoxels();
|
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 = 600.0f;
|
|
||||||
|
|
||||||
if (!_owningAgent) {
|
if (!_owningAgent) {
|
||||||
|
|
||||||
_thrust = glm::vec3(0.0f, 0.0f, 0.0f);
|
// add thrust to velocity
|
||||||
|
_velocity += _thrust * deltaTime;
|
||||||
// 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[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;}
|
|
||||||
if (_driveKeys[ROT_LEFT ]) {_bodyYawDelta += YAW_MAG * deltaTime;}
|
|
||||||
|
|
||||||
// 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_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 += THRUST_MAG *
|
|
||||||
(float)(transmitter->getTouchState()->y - TOUCH_POSITION_RANGE_HALF) / TOUCH_POSITION_RANGE_HALF *
|
|
||||||
TRANSMITTER_LIFT_SCALE *
|
|
||||||
deltaTime *
|
|
||||||
up;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update body yaw by body yaw delta
|
// update body yaw by body yaw delta
|
||||||
orientation = orientation * glm::quat(glm::radians(
|
orientation = orientation * glm::quat(glm::radians(
|
||||||
glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime));
|
glm::vec3(_bodyPitchDelta, _bodyYawDelta, _bodyRollDelta) * deltaTime));
|
||||||
|
@ -472,12 +523,22 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
_bodyYawDelta *= bodySpinMomentum;
|
_bodyYawDelta *= bodySpinMomentum;
|
||||||
_bodyRollDelta *= bodySpinMomentum;
|
_bodyRollDelta *= bodySpinMomentum;
|
||||||
|
|
||||||
// add thrust to velocity
|
// Decay velocity. If velocity is really low, increase decay to simulate static friction
|
||||||
_velocity += _thrust * deltaTime;
|
const float VELOCITY_DECAY_UNDER_THRUST = 0.2;
|
||||||
|
const float VELOCITY_FAST_DECAY = 0.6;
|
||||||
// calculate speed
|
const float VELOCITY_SLOW_DECAY = 3.0;
|
||||||
_speed = glm::length(_velocity);
|
const float VELOCITY_FAST_THRESHOLD = 2.0f;
|
||||||
|
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 {
|
||||||
|
decayConstant = VELOCITY_SLOW_DECAY;
|
||||||
|
}
|
||||||
|
decay = glm::clamp(1.0f - decayConstant * deltaTime, 0.0f, 1.0f);
|
||||||
|
_velocity *= decay;
|
||||||
|
|
||||||
//pitch and roll the body as a function of forward speed and turning delta
|
//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_PITCH_WHILE_WALKING = -20.0;
|
||||||
const float BODY_ROLL_WHILE_TURNING = 0.2;
|
const float BODY_ROLL_WHILE_TURNING = 0.2;
|
||||||
|
@ -497,29 +558,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
//the following will be used to make the avatar upright no matter what gravity is
|
//the following will be used to make the avatar upright no matter what gravity is
|
||||||
setOrientation(computeRotationFromBodyToWorldUp(tiltDecay) * orientation);
|
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 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute instantaneous acceleration
|
// Compute instantaneous acceleration
|
||||||
float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime;
|
float forwardAcceleration = glm::length(glm::dot(getBodyFrontDirection(), getVelocity() - oldVelocity)) / deltaTime;
|
||||||
const float ACCELERATION_PITCH_DECAY = 0.4f;
|
const float ACCELERATION_PITCH_DECAY = 0.4f;
|
||||||
|
@ -578,15 +616,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set head lookat position
|
|
||||||
if (!_owningAgent) {
|
|
||||||
if (_interactingOther) {
|
|
||||||
_head.setLookAtPosition(_interactingOther->caclulateAverageEyePosition());
|
|
||||||
} 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.setBodyRotation (glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
|
||||||
_head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position);
|
_head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position);
|
||||||
_head.setScale (_bodyBall[ BODY_BALL_HEAD_BASE ].radius);
|
_head.setScale (_bodyBall[ BODY_BALL_HEAD_BASE ].radius);
|
||||||
|
@ -599,6 +628,10 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
} else {
|
} else {
|
||||||
_mode = AVATAR_MODE_INTERACTING;
|
_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() {
|
void Avatar::checkForMouseRayTouching() {
|
||||||
|
@ -779,41 +812,52 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::updateCollisionWithEnvironment() {
|
void Avatar::updateCollisionWithEnvironment() {
|
||||||
|
|
||||||
glm::vec3 up = getBodyUpDirection();
|
glm::vec3 up = getBodyUpDirection();
|
||||||
float radius = _height * 0.125f;
|
float radius = _height * 0.125f;
|
||||||
|
const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f;
|
||||||
|
const float ENVIRONMENT_SURFACE_DAMPING = 0.01;
|
||||||
glm::vec3 penetration;
|
glm::vec3 penetration;
|
||||||
if (Application::getInstance()->getEnvironment()->findCapsulePenetration(
|
if (Application::getInstance()->getEnvironment()->findCapsulePenetration(
|
||||||
_position - up * (_pelvisFloatingHeight - radius),
|
_position - up * (_pelvisFloatingHeight - radius),
|
||||||
_position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) {
|
_position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) {
|
||||||
applyCollisionWithScene(penetration);
|
applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Avatar::updateCollisionWithVoxels() {
|
void Avatar::updateCollisionWithVoxels() {
|
||||||
float radius = _height * 0.125f;
|
float radius = _height * 0.125f;
|
||||||
|
const float VOXEL_ELASTICITY = 1.4f;
|
||||||
|
const float VOXEL_DAMPING = 0.0;
|
||||||
glm::vec3 penetration;
|
glm::vec3 penetration;
|
||||||
if (Application::getInstance()->getVoxels()->findCapsulePenetration(
|
if (Application::getInstance()->getVoxels()->findCapsulePenetration(
|
||||||
_position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f),
|
_position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f),
|
||||||
_position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) {
|
_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;
|
_position -= penetration;
|
||||||
static float STATIC_FRICTION_VELOCITY = 0.15f;
|
static float HALTING_VELOCITY = 0.2f;
|
||||||
static float STATIC_FRICTION_DAMPING = 0.0f;
|
|
||||||
static float KINETIC_FRICTION_DAMPING = 0.95f;
|
|
||||||
|
|
||||||
// cancel out the velocity component in the direction of penetration
|
// cancel out the velocity component in the direction of penetration
|
||||||
float penetrationLength = glm::length(penetration);
|
float penetrationLength = glm::length(penetration);
|
||||||
if (penetrationLength > EPSILON) {
|
if (penetrationLength > EPSILON) {
|
||||||
|
_elapsedTimeSinceCollision = 0.0f;
|
||||||
glm::vec3 direction = penetration / penetrationLength;
|
glm::vec3 direction = penetration / penetrationLength;
|
||||||
_velocity -= glm::dot(_velocity, direction) * direction;
|
_velocity -= glm::dot(_velocity, direction) * direction * elasticity;
|
||||||
_velocity *= KINETIC_FRICTION_DAMPING;
|
_velocity *= glm::clamp(1.f - damping, 0.0f, 1.0f);
|
||||||
// If velocity is quite low, apply static friction that takes away energy
|
if ((glm::length(_velocity) < HALTING_VELOCITY) && (glm::length(_thrust) == 0.f)) {
|
||||||
if (glm::length(_velocity) < STATIC_FRICTION_VELOCITY) {
|
// If moving really slowly after a collision, and not applying forces, stop altogether
|
||||||
_velocity *= STATIC_FRICTION_DAMPING;
|
_velocity *= 0.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -836,7 +880,6 @@ void Avatar::updateAvatarCollisions(float deltaTime) {
|
||||||
// apply forces from collision
|
// apply forces from collision
|
||||||
applyCollisionWithOtherAvatar(otherAvatar, deltaTime);
|
applyCollisionWithOtherAvatar(otherAvatar, deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// test other avatar hand position for proximity
|
// test other avatar hand position for proximity
|
||||||
glm::vec3 v(_skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position);
|
glm::vec3 v(_skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position);
|
||||||
v -= otherAvatar->getPosition();
|
v -= otherAvatar->getPosition();
|
||||||
|
@ -911,9 +954,7 @@ void Avatar::setGravity(glm::vec3 gravity) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) {
|
void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) {
|
||||||
|
|
||||||
_cameraPosition = Application::getInstance()->getCamera()->getPosition();
|
|
||||||
|
|
||||||
if (!_owningAgent && usingBigSphereCollisionTest) {
|
if (!_owningAgent && usingBigSphereCollisionTest) {
|
||||||
// show TEST big sphere
|
// show TEST big sphere
|
||||||
glColor4f(0.5f, 0.6f, 0.8f, 0.7);
|
glColor4f(0.5f, 0.6f, 0.8f, 0.7);
|
||||||
|
@ -932,7 +973,7 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) {
|
||||||
|
|
||||||
// if this is my avatar, then render my interactions with the other avatar
|
// if this is my avatar, then render my interactions with the other avatar
|
||||||
if (!_owningAgent) {
|
if (!_owningAgent) {
|
||||||
_avatarTouch.render(getCameraPosition());
|
_avatarTouch.render(Application::getInstance()->getCamera()->getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the balls
|
// Render the balls
|
||||||
|
@ -1130,32 +1171,27 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
||||||
return glm::angleAxis(angle * proportion, axis);
|
return glm::angleAxis(angle * proportion, axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Avatar::getBallRenderAlpha(int ball, bool lookingInMirror) const {
|
||||||
|
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 - DO_NOT_RENDER_INSIDE) / (RENDER_OPAQUE_OUTSIDE - DO_NOT_RENDER_INSIDE), 0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
|
void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
|
||||||
|
|
||||||
const float RENDER_OPAQUE_BEYOND = 1.0f; // Meters beyond which body is shown opaque
|
|
||||||
const float RENDER_TRANSLUCENT_BEYOND = 0.5f;
|
|
||||||
|
|
||||||
// Render the body as balls and cones
|
// Render the body as balls and cones
|
||||||
if (renderAvatarBalls || !_voxels.getVoxelURL().isValid()) {
|
if (renderAvatarBalls || !_voxels.getVoxelURL().isValid()) {
|
||||||
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
|
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
|
||||||
float distanceToCamera = glm::length(_cameraPosition - _bodyBall[b].position);
|
float alpha = getBallRenderAlpha(b, lookingInMirror);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always render other people, and render myself when beyond threshold distance
|
// 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 (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);
|
_head.render(lookingInMirror, alpha);
|
||||||
}
|
}
|
||||||
} else if (_owningAgent || distanceToCamera > RENDER_TRANSLUCENT_BEYOND
|
} else if (alpha > 0.0f) {
|
||||||
|| b == BODY_BALL_RIGHT_ELBOW
|
|
||||||
|| b == BODY_BALL_RIGHT_WRIST
|
|
||||||
|| b == BODY_BALL_RIGHT_FINGERTIPS ) {
|
|
||||||
// Render the body ball sphere
|
// Render the body ball sphere
|
||||||
if (_owningAgent || b == BODY_BALL_RIGHT_ELBOW
|
if (_owningAgent || b == BODY_BALL_RIGHT_ELBOW
|
||||||
|| b == BODY_BALL_RIGHT_WRIST
|
|| b == BODY_BALL_RIGHT_WRIST
|
||||||
|
@ -1207,7 +1243,10 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Render the body's voxels
|
// Render the body's voxels
|
||||||
_voxels.render(false);
|
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror);
|
||||||
|
if (alpha > 0.0f) {
|
||||||
|
_voxels.render(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1225,6 +1264,8 @@ void Avatar::loadData(QSettings* settings) {
|
||||||
|
|
||||||
_voxels.setVoxelURL(settings->value("voxelURL").toUrl());
|
_voxels.setVoxelURL(settings->value("voxelURL").toUrl());
|
||||||
|
|
||||||
|
_leanScale = loadSetting(settings, "leanScale", 0.5f);
|
||||||
|
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1246,6 +1287,8 @@ void Avatar::saveData(QSettings* set) {
|
||||||
|
|
||||||
set->setValue("voxelURL", _voxels.getVoxelURL());
|
set->setValue("voxelURL", _voxels.getVoxelURL());
|
||||||
|
|
||||||
|
set->setValue("leanScale", _leanScale);
|
||||||
|
|
||||||
set->endGroup();
|
set->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ public:
|
||||||
void init();
|
void init();
|
||||||
void reset();
|
void reset();
|
||||||
void simulate(float deltaTime, Transmitter* transmitter);
|
void simulate(float deltaTime, Transmitter* transmitter);
|
||||||
|
void updateThrust(float deltaTime, Transmitter * transmitter);
|
||||||
void updateHeadFromGyros(float frametime, SerialInterface * serialInterface);
|
void updateHeadFromGyros(float frametime, SerialInterface * serialInterface);
|
||||||
void updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight);
|
void updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight);
|
||||||
void addBodyYaw(float y) {_bodyYaw += y;};
|
void addBodyYaw(float y) {_bodyYaw += y;};
|
||||||
|
@ -96,6 +97,8 @@ public:
|
||||||
void setMovedHandOffset (glm::vec3 movedHandOffset ) { _movedHandOffset = movedHandOffset;}
|
void setMovedHandOffset (glm::vec3 movedHandOffset ) { _movedHandOffset = movedHandOffset;}
|
||||||
void setThrust (glm::vec3 newThrust ) { _thrust = newThrust; };
|
void setThrust (glm::vec3 newThrust ) { _thrust = newThrust; };
|
||||||
void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors);}
|
void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors);}
|
||||||
|
void setVelocity (const glm::vec3 velocity ) { _velocity = velocity; };
|
||||||
|
void setLeanScale (float scale ) { _leanScale = scale;}
|
||||||
void setGravity (glm::vec3 gravity);
|
void setGravity (glm::vec3 gravity);
|
||||||
void setMouseRay (const glm::vec3 &origin, const glm::vec3 &direction);
|
void setMouseRay (const glm::vec3 &origin, const glm::vec3 &direction);
|
||||||
void setOrientation (const glm::quat& orientation);
|
void setOrientation (const glm::quat& orientation);
|
||||||
|
@ -115,17 +118,24 @@ public:
|
||||||
float getSpeed () const { return _speed;}
|
float getSpeed () const { return _speed;}
|
||||||
float getHeight () const { return _height;}
|
float getHeight () const { return _height;}
|
||||||
AvatarMode getMode () const { return _mode;}
|
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 getAbsoluteHeadYaw () const;
|
||||||
float getAbsoluteHeadPitch () const;
|
float getAbsoluteHeadPitch () const;
|
||||||
Head& getHead () {return _head; }
|
Head& getHead () {return _head; }
|
||||||
glm::quat getOrientation () const;
|
glm::quat getOrientation () const;
|
||||||
glm::quat getWorldAlignedOrientation() const;
|
glm::quat getWorldAlignedOrientation() const;
|
||||||
|
|
||||||
|
glm::vec3 getUprightHeadPosition() const;
|
||||||
|
|
||||||
AvatarVoxelSystem* getVoxels() { return &_voxels; }
|
AvatarVoxelSystem* getVoxels() { return &_voxels; }
|
||||||
|
|
||||||
// Set what driving keys are being pressed to control thrust levels
|
// Set what driving keys are being pressed to control thrust levels
|
||||||
void setDriveKeys(int key, bool val) { _driveKeys[key] = val; };
|
void setDriveKeys(int key, bool val) { _driveKeys[key] = val; };
|
||||||
bool getDriveKeys(int key) { return _driveKeys[key]; };
|
bool getDriveKeys(int key) { return _driveKeys[key]; };
|
||||||
|
void jump() { _shouldJump = true; };
|
||||||
|
|
||||||
// Set/Get update the thrust that will move the avatar around
|
// Set/Get update the thrust that will move the avatar around
|
||||||
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
||||||
|
@ -175,32 +185,37 @@ private:
|
||||||
glm::vec3 _movedHandOffset;
|
glm::vec3 _movedHandOffset;
|
||||||
AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ];
|
AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ];
|
||||||
AvatarMode _mode;
|
AvatarMode _mode;
|
||||||
glm::vec3 _cameraPosition;
|
|
||||||
glm::vec3 _handHoldingPosition;
|
glm::vec3 _handHoldingPosition;
|
||||||
glm::vec3 _velocity;
|
glm::vec3 _velocity;
|
||||||
glm::vec3 _thrust;
|
glm::vec3 _thrust;
|
||||||
|
bool _shouldJump;
|
||||||
float _speed;
|
float _speed;
|
||||||
float _maxArmLength;
|
float _maxArmLength;
|
||||||
glm::quat _righting;
|
float _leanScale;
|
||||||
int _driveKeys[MAX_DRIVE_KEYS];
|
int _driveKeys[MAX_DRIVE_KEYS];
|
||||||
float _pelvisStandingHeight;
|
float _pelvisStandingHeight;
|
||||||
float _pelvisFloatingHeight;
|
float _pelvisFloatingHeight;
|
||||||
|
float _pelvisToHeadLength;
|
||||||
float _height;
|
float _height;
|
||||||
Balls* _balls;
|
Balls* _balls;
|
||||||
AvatarTouch _avatarTouch;
|
AvatarTouch _avatarTouch;
|
||||||
float _distanceToNearestAvatar; // How close is the nearest avatar?
|
float _distanceToNearestAvatar; // How close is the nearest avatar?
|
||||||
glm::vec3 _gravity;
|
glm::vec3 _gravity;
|
||||||
glm::vec3 _worldUpDirection;
|
glm::vec3 _worldUpDirection;
|
||||||
glm::vec3 _mouseRayOrigin;
|
glm::vec3 _mouseRayOrigin;
|
||||||
glm::vec3 _mouseRayDirection;
|
glm::vec3 _mouseRayDirection;
|
||||||
Avatar* _interactingOther;
|
Avatar* _interactingOther;
|
||||||
bool _isMouseTurningRight;
|
bool _isMouseTurningRight;
|
||||||
|
float _elapsedTimeMoving; // Timers to drive camera transitions when moving
|
||||||
|
float _elapsedTimeStopped;
|
||||||
|
float _elapsedTimeSinceCollision;
|
||||||
|
|
||||||
AvatarVoxelSystem _voxels;
|
AvatarVoxelSystem _voxels;
|
||||||
|
|
||||||
// private methods...
|
// 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;
|
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
|
||||||
|
float getBallRenderAlpha(int ball, bool lookingInMirror) const;
|
||||||
void renderBody(bool lookingInMirror, bool renderAvatarBalls);
|
void renderBody(bool lookingInMirror, bool renderAvatarBalls);
|
||||||
void initializeBodyBalls();
|
void initializeBodyBalls();
|
||||||
void resetBodyBalls();
|
void resetBodyBalls();
|
||||||
|
@ -213,7 +228,7 @@ private:
|
||||||
void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime );
|
void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime );
|
||||||
void updateCollisionWithEnvironment();
|
void updateCollisionWithEnvironment();
|
||||||
void updateCollisionWithVoxels();
|
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 applyCollisionWithOtherAvatar( Avatar * other, float deltaTime );
|
||||||
void checkForMouseRayTouching();
|
void checkForMouseRayTouching();
|
||||||
void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2);
|
void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2);
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "renderer/ProgramObject.h"
|
#include "renderer/ProgramObject.h"
|
||||||
|
|
||||||
const float AVATAR_TREE_SCALE = 1.0f;
|
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;
|
const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL;
|
||||||
|
|
||||||
AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) :
|
AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) :
|
||||||
|
|
|
@ -5,12 +5,16 @@
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
|
||||||
#include <glm/gtx/quaternion.hpp>
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
|
||||||
|
#include <QImage>
|
||||||
|
|
||||||
|
#include <AgentList.h>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
#include "Head.h"
|
#include "Head.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include <vector>
|
#include "renderer/ProgramObject.h"
|
||||||
#include <lodepng.h>
|
|
||||||
#include <AgentList.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -35,9 +39,8 @@ const float IRIS_RADIUS = 0.007;
|
||||||
const float IRIS_PROTRUSION = 0.0145f;
|
const float IRIS_PROTRUSION = 0.0145f;
|
||||||
const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png";
|
const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png";
|
||||||
|
|
||||||
unsigned int IRIS_TEXTURE_WIDTH = 768;
|
ProgramObject* Head::_irisProgram = 0;
|
||||||
unsigned int IRIS_TEXTURE_HEIGHT = 498;
|
GLuint Head::_irisTextureID;
|
||||||
vector<unsigned char> irisTexture;
|
|
||||||
|
|
||||||
Head::Head(Avatar* owningAvatar) :
|
Head::Head(Avatar* owningAvatar) :
|
||||||
HeadData((AvatarData*)owningAvatar),
|
HeadData((AvatarData*)owningAvatar),
|
||||||
|
@ -56,7 +59,6 @@ Head::Head(Avatar* owningAvatar) :
|
||||||
_mouthPosition(0.0f, 0.0f, 0.0f),
|
_mouthPosition(0.0f, 0.0f, 0.0f),
|
||||||
_scale(1.0f),
|
_scale(1.0f),
|
||||||
_browAudioLift(0.0f),
|
_browAudioLift(0.0f),
|
||||||
_lookingAtSomething(false),
|
|
||||||
_gravity(0.0f, -1.0f, 0.0f),
|
_gravity(0.0f, -1.0f, 0.0f),
|
||||||
_lastLoudness(0.0f),
|
_lastLoudness(0.0f),
|
||||||
_averageLoudness(0.0f),
|
_averageLoudness(0.0f),
|
||||||
|
@ -66,13 +68,35 @@ Head::Head(Avatar* owningAvatar) :
|
||||||
_lookingInMirror(false),
|
_lookingInMirror(false),
|
||||||
_renderLookatVectors(false),
|
_renderLookatVectors(false),
|
||||||
_mohawkTriangleFan(NULL),
|
_mohawkTriangleFan(NULL),
|
||||||
_mohawkColors(NULL)
|
_mohawkColors(NULL),
|
||||||
|
_saccade(0.0f, 0.0f, 0.0f),
|
||||||
|
_saccadeTarget(0.0f, 0.0f, 0.0f)
|
||||||
{
|
{
|
||||||
if (USING_PHYSICAL_MOHAWK) {
|
if (USING_PHYSICAL_MOHAWK) {
|
||||||
resetHairPhysics();
|
resetHairPhysics();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Head::init() {
|
||||||
|
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);
|
||||||
|
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() {
|
void Head::reset() {
|
||||||
_yaw = _pitch = _roll = 0.0f;
|
_yaw = _pitch = _roll = 0.0f;
|
||||||
_leanForward = _leanSideways = 0.0f;
|
_leanForward = _leanSideways = 0.0f;
|
||||||
|
@ -101,32 +125,19 @@ void Head::resetHairPhysics() {
|
||||||
|
|
||||||
|
|
||||||
void Head::simulate(float deltaTime, bool isMine) {
|
void Head::simulate(float deltaTime, bool isMine) {
|
||||||
|
|
||||||
const float HEAD_MOTION_DECAY = 0.00;
|
|
||||||
|
|
||||||
/*
|
// Update eye saccades
|
||||||
// Decay head back to center if turned on
|
const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f;
|
||||||
if (isMine && _returnHeadToCenter) {
|
const float AVERAGE_SACCADE_INTERVAL = 4.0f;
|
||||||
|
const float MICROSACCADE_MAGNITUDE = 0.002f;
|
||||||
|
const float SACCADE_MAGNITUDE = 0.04;
|
||||||
|
|
||||||
// Decay rotation back toward center
|
if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) {
|
||||||
_pitch *= (1.0f - HEAD_MOTION_DECAY * _returnSpringScale * deltaTime);
|
_saccadeTarget = MICROSACCADE_MAGNITUDE * randVector();
|
||||||
_yaw *= (1.0f - HEAD_MOTION_DECAY * _returnSpringScale * deltaTime);
|
} else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) {
|
||||||
_roll *= (1.0f - HEAD_MOTION_DECAY * _returnSpringScale * deltaTime);
|
_saccadeTarget = SACCADE_MAGNITUDE * randVector();
|
||||||
}
|
}
|
||||||
|
_saccade += (_saccadeTarget - _saccade) * 0.50f;
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Update audio trailing average for rendering facial animations
|
// Update audio trailing average for rendering facial animations
|
||||||
const float AUDIO_AVERAGING_SECS = 0.05;
|
const float AUDIO_AVERAGING_SECS = 0.05;
|
||||||
|
@ -147,30 +158,13 @@ void Head::simulate(float deltaTime, bool isMine) {
|
||||||
|
|
||||||
_browAudioLift *= 0.7f;
|
_browAudioLift *= 0.7f;
|
||||||
|
|
||||||
// based on the nature of the lookat position, determine if the eyes can look / are looking at it.
|
// based on the nature of the lookat position, determine if the eyes can look / are looking at it.
|
||||||
determineIfLookingAtSomething();
|
|
||||||
|
|
||||||
if (USING_PHYSICAL_MOHAWK) {
|
if (USING_PHYSICAL_MOHAWK) {
|
||||||
updateHairPhysics(deltaTime);
|
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 - caclulateAverageEyePosition());
|
|
||||||
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() {
|
void Head::calculateGeometry() {
|
||||||
//generate orientation directions
|
//generate orientation directions
|
||||||
glm::quat orientation = getOrientation();
|
glm::quat orientation = getOrientation();
|
||||||
|
@ -202,7 +196,7 @@ void Head::calculateGeometry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Head::render(bool lookingInMirror, glm::vec3 cameraPosition, float alpha) {
|
void Head::render(bool lookingInMirror, float alpha) {
|
||||||
|
|
||||||
_renderAlpha = alpha;
|
_renderAlpha = alpha;
|
||||||
_lookingInMirror = lookingInMirror;
|
_lookingInMirror = lookingInMirror;
|
||||||
|
@ -212,14 +206,14 @@ void Head::render(bool lookingInMirror, glm::vec3 cameraPosition, float alpha) {
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glEnable(GL_RESCALE_NORMAL);
|
glEnable(GL_RESCALE_NORMAL);
|
||||||
|
|
||||||
renderMohawk(cameraPosition);
|
renderMohawk();
|
||||||
renderHeadSphere();
|
renderHeadSphere();
|
||||||
renderEyeBalls();
|
renderEyeBalls();
|
||||||
renderEars();
|
renderEars();
|
||||||
renderMouth();
|
renderMouth();
|
||||||
renderEyeBrows();
|
renderEyeBrows();
|
||||||
|
|
||||||
if (_renderLookatVectors && _lookingAtSomething) {
|
if (_renderLookatVectors) {
|
||||||
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
|
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,7 +250,7 @@ void Head::createMohawk() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Head::renderMohawk(glm::vec3 cameraPosition) {
|
void Head::renderMohawk() {
|
||||||
|
|
||||||
if (!_mohawkTriangleFan) {
|
if (!_mohawkTriangleFan) {
|
||||||
createMohawk();
|
createMohawk();
|
||||||
|
@ -267,7 +261,7 @@ void Head::renderMohawk(glm::vec3 cameraPosition) {
|
||||||
|
|
||||||
glm::vec3 baseAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition;
|
glm::vec3 baseAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition;
|
||||||
glm::vec3 midAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition;
|
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 basePerpendicular = glm::normalize(glm::cross(baseAxis, viewVector));
|
||||||
glm::vec3 midPerpendicular = glm::normalize(glm::cross(midAxis, viewVector));
|
glm::vec3 midPerpendicular = glm::normalize(glm::cross(midAxis, viewVector));
|
||||||
|
@ -468,22 +462,11 @@ void Head::renderEyeBrows() {
|
||||||
|
|
||||||
void Head::renderEyeBalls() {
|
void Head::renderEyeBalls() {
|
||||||
|
|
||||||
if (::irisTexture.size() == 0) {
|
// setup the texture to be used on each iris
|
||||||
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();
|
GLUquadric* irisQuadric = gluNewQuadric();
|
||||||
gluQuadricTexture(irisQuadric, GL_TRUE);
|
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);
|
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]);
|
|
||||||
|
|
||||||
// render white ball of left eyeball
|
// render white ball of left eyeball
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
@ -492,45 +475,6 @@ void Head::renderEyeBalls() {
|
||||||
gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30);
|
gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
glm::vec3 front = getFrontDirection();
|
|
||||||
|
|
||||||
// render left iris
|
|
||||||
glPushMatrix(); {
|
|
||||||
glTranslatef(_leftEyePosition.x, _leftEyePosition.y, _leftEyePosition.z); //translate to eyeball position
|
|
||||||
|
|
||||||
glPushMatrix();
|
|
||||||
|
|
||||||
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);
|
|
||||||
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
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
gluSphere(irisQuadric, IRIS_RADIUS, 15, 15);
|
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
|
||||||
glPopMatrix();
|
|
||||||
|
|
||||||
//render white ball of right eyeball
|
//render white ball of right eyeball
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glColor3fv(EYEBALL_COLOR);
|
glColor3fv(EYEBALL_COLOR);
|
||||||
|
@ -538,43 +482,50 @@ void Head::renderEyeBalls() {
|
||||||
gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30);
|
gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
||||||
|
_irisProgram->bind();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, _irisTextureID);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
glm::vec3 front = getFrontDirection();
|
||||||
|
|
||||||
|
// render left iris
|
||||||
|
glPushMatrix(); {
|
||||||
|
glTranslatef(_leftEyePosition.x, _leftEyePosition.y, _leftEyePosition.z); //translate to eyeball position
|
||||||
|
glPushMatrix();
|
||||||
|
//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();
|
||||||
|
}
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
// render right iris
|
// render right iris
|
||||||
glPushMatrix(); {
|
glPushMatrix(); {
|
||||||
glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); //translate to eyeball position
|
glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); //translate to eyeball position
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
|
||||||
if (_lookingAtSomething) {
|
|
||||||
|
|
||||||
//rotate the eyeball to aim towards the lookat position
|
|
||||||
glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - _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 towards the lookat position
|
||||||
|
glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _rightEyePosition);
|
||||||
//rotate the eyeball to aim straight ahead
|
glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP);
|
||||||
glm::vec3 rotationAxisToHeadFront = glm::cross(front, IDENTITY_UP);
|
float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP);
|
||||||
float angleToHeadFront = 180.0f - angleBetween(front, IDENTITY_UP);
|
glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z);
|
||||||
glRotatef(angleToHeadFront, rotationAxisToHeadFront.x, rotationAxisToHeadFront.y, rotationAxisToHeadFront.z);
|
glRotatef(180.0f, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations
|
||||||
|
glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f);
|
||||||
//set the amount of roll (for correction after previous rotations)
|
glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris
|
||||||
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
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
gluSphere(irisQuadric, IRIS_RADIUS, 15, 15);
|
gluSphere(irisQuadric, IRIS_RADIUS, 15, 15);
|
||||||
glDisable(GL_TEXTURE_2D);
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_irisProgram->release();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
glDisable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
// delete the iris quadric now that we're done with it
|
// delete the iris quadric now that we're done with it
|
||||||
gluDeleteQuadric(irisQuadric);
|
gluDeleteQuadric(irisQuadric);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
|
|
@ -26,15 +26,17 @@ enum eyeContactTargets
|
||||||
const int NUM_HAIR_TUFTS = 4;
|
const int NUM_HAIR_TUFTS = 4;
|
||||||
|
|
||||||
class Avatar;
|
class Avatar;
|
||||||
|
class ProgramObject;
|
||||||
|
|
||||||
class Head : public HeadData {
|
class Head : public HeadData {
|
||||||
public:
|
public:
|
||||||
Head(Avatar* owningAvatar);
|
Head(Avatar* owningAvatar);
|
||||||
|
|
||||||
|
void init();
|
||||||
void reset();
|
void reset();
|
||||||
void simulate(float deltaTime, bool isMine);
|
void simulate(float deltaTime, bool isMine);
|
||||||
void render(bool lookingInMirror, glm::vec3 cameraPosition, float alpha);
|
void render(bool lookingInMirror, float alpha);
|
||||||
void renderMohawk(glm::vec3 cameraPosition);
|
void renderMohawk();
|
||||||
|
|
||||||
void setScale (float scale ) { _scale = scale; }
|
void setScale (float scale ) { _scale = scale; }
|
||||||
void setPosition (glm::vec3 position ) { _position = position; }
|
void setPosition (glm::vec3 position ) { _position = position; }
|
||||||
|
@ -55,7 +57,7 @@ public:
|
||||||
|
|
||||||
const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
||||||
float getAverageLoudness() {return _averageLoudness;};
|
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 yawRate;
|
||||||
float noise;
|
float noise;
|
||||||
|
@ -91,7 +93,6 @@ private:
|
||||||
glm::vec3 _mouthPosition;
|
glm::vec3 _mouthPosition;
|
||||||
float _scale;
|
float _scale;
|
||||||
float _browAudioLift;
|
float _browAudioLift;
|
||||||
bool _lookingAtSomething;
|
|
||||||
glm::vec3 _gravity;
|
glm::vec3 _gravity;
|
||||||
float _lastLoudness;
|
float _lastLoudness;
|
||||||
float _averageLoudness;
|
float _averageLoudness;
|
||||||
|
@ -103,6 +104,11 @@ private:
|
||||||
HairTuft _hairTuft[NUM_HAIR_TUFTS];
|
HairTuft _hairTuft[NUM_HAIR_TUFTS];
|
||||||
glm::vec3* _mohawkTriangleFan;
|
glm::vec3* _mohawkTriangleFan;
|
||||||
glm::vec3* _mohawkColors;
|
glm::vec3* _mohawkColors;
|
||||||
|
glm::vec3 _saccade;
|
||||||
|
glm::vec3 _saccadeTarget;
|
||||||
|
|
||||||
|
static ProgramObject* _irisProgram;
|
||||||
|
static GLuint _irisTextureID;
|
||||||
|
|
||||||
// private methods
|
// private methods
|
||||||
void createMohawk();
|
void createMohawk();
|
||||||
|
@ -113,7 +119,6 @@ private:
|
||||||
void renderMouth();
|
void renderMouth();
|
||||||
void renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition);
|
void renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition);
|
||||||
void calculateGeometry();
|
void calculateGeometry();
|
||||||
void determineIfLookingAtSomething();
|
|
||||||
void resetHairPhysics();
|
void resetHairPhysics();
|
||||||
void updateHairPhysics(float deltaTime);
|
void updateHairPhysics(float deltaTime);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "SerialInterface.h"
|
#include "SerialInterface.h"
|
||||||
|
#include "SharedUtil.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include <glm/gtx/vector_angle.hpp>
|
#include <glm/gtx/vector_angle.hpp>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -155,11 +156,11 @@ void SerialInterface::renderLevels(int width, int height) {
|
||||||
// Acceleration rates
|
// Acceleration rates
|
||||||
glColor4f(1, 1, 1, 1);
|
glColor4f(1, 1, 1, 1);
|
||||||
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 42);
|
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, 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, 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
|
// Estimated Position
|
||||||
glColor4f(0, 1, 1, 1);
|
glColor4f(0, 1, 1, 1);
|
||||||
|
@ -217,6 +218,7 @@ void SerialInterface::readData(float deltaTime) {
|
||||||
|
|
||||||
_lastAcceleration = glm::vec3(-accelXRate, -accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2;
|
_lastAcceleration = glm::vec3(-accelXRate, -accelYRate, -accelZRate) * LSB_TO_METERS_PER_SECOND2;
|
||||||
|
|
||||||
|
|
||||||
int rollRate, yawRate, pitchRate;
|
int rollRate, yawRate, pitchRate;
|
||||||
|
|
||||||
convertHexToInt(sensorBuffer + 22, rollRate);
|
convertHexToInt(sensorBuffer + 22, rollRate);
|
||||||
|
@ -225,35 +227,87 @@ void SerialInterface::readData(float deltaTime) {
|
||||||
|
|
||||||
// Convert the integer rates to floats
|
// 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.
|
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;
|
glm::vec3 rotationRates;
|
||||||
_lastRotationRates[1] = ((float) -yawRate) * LSB_TO_DEGREES_PER_SECOND;
|
rotationRates[0] = ((float) -pitchRate) * LSB_TO_DEGREES_PER_SECOND;
|
||||||
_lastRotationRates[2] = ((float) -rollRate) * LSB_TO_DEGREES_PER_SECOND;
|
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;
|
||||||
|
|
||||||
// Update raw rotation estimates
|
// Update raw rotation estimates
|
||||||
glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) *
|
glm::quat estimatedRotation = glm::quat(glm::radians(_estimatedRotation)) *
|
||||||
glm::quat(glm::radians(deltaTime * (_lastRotationRates - _averageRotationRates)));
|
glm::quat(glm::radians(deltaTime * _lastRotationRates));
|
||||||
|
|
||||||
|
// Update acceleration estimate: first, subtract gravity as rotated into current frame
|
||||||
|
_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;
|
||||||
|
_estimatedAcceleration -= _averageAcceleration;
|
||||||
|
|
||||||
|
// Consider updating our angular velocity/acceleration to linear acceleration mapping
|
||||||
|
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;
|
||||||
|
glm::vec3 error = _estimatedAcceleration - predictedAcceleration;
|
||||||
|
|
||||||
|
// 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.001f;
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate estimated acceleration into global rotation frame
|
||||||
|
_estimatedAcceleration = estimatedRotation * _estimatedAcceleration;
|
||||||
|
|
||||||
// Update estimated position and velocity
|
// Update estimated position and velocity
|
||||||
float const DECAY_VELOCITY = 0.95f;
|
float const DECAY_VELOCITY = 0.975f;
|
||||||
float const DECAY_POSITION = 0.95f;
|
float const DECAY_POSITION = 0.975f;
|
||||||
_estimatedVelocity += deltaTime * (_lastAcceleration - _averageAcceleration);
|
_estimatedVelocity += deltaTime * _estimatedAcceleration;
|
||||||
_estimatedPosition += deltaTime * _estimatedVelocity;
|
_estimatedPosition += deltaTime * _estimatedVelocity;
|
||||||
_estimatedVelocity *= DECAY_VELOCITY;
|
_estimatedVelocity *= DECAY_VELOCITY;
|
||||||
_estimatedPosition *= DECAY_POSITION;
|
_estimatedPosition *= DECAY_POSITION;
|
||||||
|
|
||||||
// Accumulate a set of initial baseline readings for setting gravity
|
// Accumulate a set of initial baseline readings for setting gravity
|
||||||
if (totalSamples == 0) {
|
if (totalSamples == 0) {
|
||||||
_averageRotationRates = _lastRotationRates;
|
|
||||||
_averageAcceleration = _lastAcceleration;
|
|
||||||
_gravity = _lastAcceleration;
|
_gravity = _lastAcceleration;
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
if (totalSamples < GRAVITY_SAMPLES) {
|
||||||
_gravity = (1.f - 1.f/(float)GRAVITY_SAMPLES) * _gravity +
|
_gravity = (1.f - 1.f/(float)GRAVITY_SAMPLES) * _gravity +
|
||||||
1.f/(float)GRAVITY_SAMPLES * _lastAcceleration;
|
1.f/(float)GRAVITY_SAMPLES * _lastAcceleration;
|
||||||
|
@ -299,6 +353,7 @@ void SerialInterface::resetAverages() {
|
||||||
_estimatedRotation = glm::vec3(0, 0, 0);
|
_estimatedRotation = glm::vec3(0, 0, 0);
|
||||||
_estimatedPosition = glm::vec3(0, 0, 0);
|
_estimatedPosition = glm::vec3(0, 0, 0);
|
||||||
_estimatedVelocity = glm::vec3(0, 0, 0);
|
_estimatedVelocity = glm::vec3(0, 0, 0);
|
||||||
|
_estimatedAcceleration = glm::vec3(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialInterface::resetSerial() {
|
void SerialInterface::resetSerial() {
|
||||||
|
|
|
@ -32,18 +32,27 @@ public:
|
||||||
_estimatedPosition(0, 0, 0),
|
_estimatedPosition(0, 0, 0),
|
||||||
_estimatedVelocity(0, 0, 0),
|
_estimatedVelocity(0, 0, 0),
|
||||||
_lastAcceleration(0, 0, 0),
|
_lastAcceleration(0, 0, 0),
|
||||||
_lastRotationRates(0, 0, 0)
|
_lastRotationRates(0, 0, 0),
|
||||||
|
_angularVelocityToLinearAccel( // experimentally derived initial values
|
||||||
|
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.001f,
|
||||||
|
-0.002f, -0.002f, 0.0f)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void pair();
|
void pair();
|
||||||
void readData(float deltaTime);
|
void readData(float deltaTime);
|
||||||
const float getLastPitchRate() const { return _lastRotationRates[0] - _averageRotationRates[0]; }
|
const float getLastPitchRate() const { return _lastRotationRates[0]; }
|
||||||
const float getLastYawRate() const { return _lastRotationRates[1] - _averageRotationRates[1]; }
|
const float getLastYawRate() const { return _lastRotationRates[1]; }
|
||||||
const float getLastRollRate() const { return _lastRotationRates[2] - _averageRotationRates[2]; }
|
const float getLastRollRate() const { return _lastRotationRates[2]; }
|
||||||
const glm::vec3& getLastRotationRates() const { return _lastRotationRates; };
|
const glm::vec3& getLastRotationRates() const { return _lastRotationRates; };
|
||||||
const glm::vec3& getEstimatedRotation() const { return _estimatedRotation; };
|
const glm::vec3& getEstimatedRotation() const { return _estimatedRotation; };
|
||||||
const glm::vec3& getEstimatedPosition() const { return _estimatedPosition; };
|
const glm::vec3& getEstimatedPosition() const { return _estimatedPosition; };
|
||||||
const glm::vec3& getEstimatedVelocity() const { return _estimatedVelocity; };
|
const glm::vec3& getEstimatedVelocity() const { return _estimatedVelocity; };
|
||||||
|
const glm::vec3& getEstimatedAcceleration() const { return _estimatedAcceleration; };
|
||||||
const glm::vec3& getLastAcceleration() const { return _lastAcceleration; };
|
const glm::vec3& getLastAcceleration() const { return _lastAcceleration; };
|
||||||
const glm::vec3& getGravity() const { return _gravity; };
|
const glm::vec3& getGravity() const { return _gravity; };
|
||||||
|
|
||||||
|
@ -64,8 +73,12 @@ private:
|
||||||
glm::vec3 _estimatedRotation;
|
glm::vec3 _estimatedRotation;
|
||||||
glm::vec3 _estimatedPosition;
|
glm::vec3 _estimatedPosition;
|
||||||
glm::vec3 _estimatedVelocity;
|
glm::vec3 _estimatedVelocity;
|
||||||
|
glm::vec3 _estimatedAcceleration;
|
||||||
glm::vec3 _lastAcceleration;
|
glm::vec3 _lastAcceleration;
|
||||||
glm::vec3 _lastRotationRates;
|
glm::vec3 _lastRotationRates;
|
||||||
|
|
||||||
|
glm::mat3 _angularVelocityToLinearAccel;
|
||||||
|
glm::mat3 _angularAccelToLinearAccel;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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++) {
|
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
|
||||||
if (joint[b].parent == AVATAR_JOINT_NULL) {
|
if (joint[b].parent == AVATAR_JOINT_NULL) {
|
||||||
joint[b].rotation = orientation;
|
joint[b].absoluteRotation = orientation * joint[b].rotation;
|
||||||
joint[b].position = position;
|
joint[b].position = position;
|
||||||
}
|
}
|
||||||
else {
|
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;
|
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;
|
joint[b].position += rotatedJointVector;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,6 +174,13 @@ float Skeleton::getPelvisFloatingHeight() {
|
||||||
FLOATING_HEIGHT;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ public:
|
||||||
float getHeight();
|
float getHeight();
|
||||||
float getPelvisStandingHeight();
|
float getPelvisStandingHeight();
|
||||||
float getPelvisFloatingHeight();
|
float getPelvisFloatingHeight();
|
||||||
|
float getPelvisToHeadLength();
|
||||||
//glm::vec3 getJointVectorFromParent(AvatarJointID jointID) {return joint[jointID].position - joint[joint[jointID].parent].position; }
|
//glm::vec3 getJointVectorFromParent(AvatarJointID jointID) {return joint[jointID].position - joint[joint[jointID].parent].position; }
|
||||||
|
|
||||||
struct AvatarJoint
|
struct AvatarJoint
|
||||||
|
@ -68,6 +69,7 @@ public:
|
||||||
glm::quat absoluteBindPoseRotation; // the absolute rotation when the avatar is in the "T-pose"
|
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
|
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 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
|
float length; // the length of vector connecting the joint and its parent
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -70,9 +70,7 @@ void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) {
|
||||||
|
|
||||||
// Update estimated absolute position from rotation rates
|
// Update estimated absolute position from rotation rates
|
||||||
_estimatedRotation += _lastRotationRate * DELTA_TIME;
|
_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)
|
// Sensor Fusion! Slowly adjust estimated rotation to be relative to gravity (average acceleration)
|
||||||
const float GRAVITY_FOLLOW_RATE = 1.f;
|
const float GRAVITY_FOLLOW_RATE = 1.f;
|
||||||
float rollAngle = angleBetween(glm::vec3(_lastAcceleration.x, _lastAcceleration.y, 0.f), glm::vec3(0,-1,0)) *
|
float rollAngle = angleBetween(glm::vec3(_lastAcceleration.x, _lastAcceleration.y, 0.f), glm::vec3(0,-1,0)) *
|
||||||
|
|
|
@ -267,6 +267,11 @@ double diffclock(timeval *clock1,timeval *clock2)
|
||||||
return diffms;
|
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* textRenderer(int mono) {
|
||||||
static TextRenderer* monoRenderer = new TextRenderer(MONO_FONT_FAMILY);
|
static TextRenderer* monoRenderer = new TextRenderer(MONO_FONT_FAMILY);
|
||||||
static TextRenderer* proportionalRenderer = new TextRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT);
|
static TextRenderer* proportionalRenderer = new TextRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT);
|
||||||
|
@ -498,9 +503,9 @@ void runTimingTests() {
|
||||||
}
|
}
|
||||||
|
|
||||||
float loadSetting(QSettings* settings, const char* name, float defaultValue) {
|
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)) {
|
if (isnan(value)) {
|
||||||
value = defaultValue;
|
value = defaultValue;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float head_yaw);
|
||||||
|
|
||||||
float randFloat();
|
float randFloat();
|
||||||
|
const glm::vec3 randVector();
|
||||||
|
|
||||||
void render_world_box();
|
void render_world_box();
|
||||||
int widthText(float scale, int mono, char const* string);
|
int widthText(float scale, int mono, char const* string);
|
||||||
float widthChar(float scale, int mono, char ch);
|
float widthChar(float scale, int mono, char ch);
|
||||||
|
|
|
@ -165,15 +165,15 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
|
|
||||||
void VoxelSystem::setupNewVoxelsForDrawing() {
|
void VoxelSystem::setupNewVoxelsForDrawing() {
|
||||||
PerformanceWarning warn(_renderWarningsOn, "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated
|
PerformanceWarning warn(_renderWarningsOn, "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated
|
||||||
double start = usecTimestampNow();
|
long long start = usecTimestampNow();
|
||||||
double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0;
|
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
|
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)) {
|
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
|
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 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))
|
if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS))
|
||||||
&& !isViewChanging() && hasViewChanged()) {
|
&& !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.
|
// VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary.
|
||||||
cleanupRemovedVoxels();
|
cleanupRemovedVoxels();
|
||||||
|
|
||||||
double endViewCulling = usecTimestampNow();
|
long long endViewCulling = usecTimestampNow();
|
||||||
_lastViewCullingElapsed = (endViewCulling - start) / 1000.0;
|
_lastViewCullingElapsed = (endViewCulling - start) / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool didWriteFullVBO = _writeRenderFullVBO;
|
bool didWriteFullVBO = _writeRenderFullVBO;
|
||||||
|
@ -226,8 +226,8 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
|
||||||
|
|
||||||
pthread_mutex_unlock(&_bufferWriteLock);
|
pthread_mutex_unlock(&_bufferWriteLock);
|
||||||
|
|
||||||
double end = usecTimestampNow();
|
long long end = usecTimestampNow();
|
||||||
double elapsedmsec = (end - start) / 1000.0;
|
long long elapsedmsec = (end - start) / 1000;
|
||||||
_setupNewVoxelsForDrawingLastFinished = end;
|
_setupNewVoxelsForDrawingLastFinished = end;
|
||||||
_setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
|
_setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
|
||||||
|
|
||||||
injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket));
|
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) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "Agent.h"
|
#include "Agent.h"
|
||||||
#include "AgentTypes.h"
|
#include "AgentTypes.h"
|
||||||
|
@ -62,7 +64,7 @@ Agent::~Agent() {
|
||||||
|
|
||||||
// Names of Agent Types
|
// Names of Agent Types
|
||||||
const char* AGENT_TYPE_NAME_DOMAIN = "Domain";
|
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_INTERFACE = "Client Interface";
|
||||||
const char* AGENT_TYPE_NAME_AUDIO_MIXER = "Audio Mixer";
|
const char* AGENT_TYPE_NAME_AUDIO_MIXER = "Audio Mixer";
|
||||||
const char* AGENT_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer";
|
const char* AGENT_TYPE_NAME_AVATAR_MIXER = "Avatar Mixer";
|
||||||
|
@ -74,8 +76,8 @@ const char* Agent::getTypeName() const {
|
||||||
switch (this->_type) {
|
switch (this->_type) {
|
||||||
case AGENT_TYPE_DOMAIN:
|
case AGENT_TYPE_DOMAIN:
|
||||||
return AGENT_TYPE_NAME_DOMAIN;
|
return AGENT_TYPE_NAME_DOMAIN;
|
||||||
case AGENT_TYPE_VOXEL:
|
case AGENT_TYPE_VOXEL_SERVER:
|
||||||
return AGENT_TYPE_NAME_VOXEL;
|
return AGENT_TYPE_NAME_VOXEL_SERVER;
|
||||||
case AGENT_TYPE_AVATAR:
|
case AGENT_TYPE_AVATAR:
|
||||||
return AGENT_TYPE_NAME_INTERFACE;
|
return AGENT_TYPE_NAME_INTERFACE;
|
||||||
case AGENT_TYPE_AUDIO_MIXER:
|
case AGENT_TYPE_AUDIO_MIXER:
|
||||||
|
|
|
@ -37,11 +37,11 @@ public:
|
||||||
uint16_t getAgentID() const { return _agentID; }
|
uint16_t getAgentID() const { return _agentID; }
|
||||||
void setAgentID(uint16_t agentID) { _agentID = agentID;}
|
void setAgentID(uint16_t agentID) { _agentID = agentID;}
|
||||||
|
|
||||||
double getWakeMicrostamp() const { return _wakeMicrostamp; }
|
long long getWakeMicrostamp() const { return _wakeMicrostamp; }
|
||||||
void setWakeMicrostamp(double wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; }
|
void setWakeMicrostamp(long long wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; }
|
||||||
|
|
||||||
double getLastHeardMicrostamp() const { return _lastHeardMicrostamp; }
|
long long getLastHeardMicrostamp() const { return _lastHeardMicrostamp; }
|
||||||
void setLastHeardMicrostamp(double lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; }
|
void setLastHeardMicrostamp(long long lastHeardMicrostamp) { _lastHeardMicrostamp = lastHeardMicrostamp; }
|
||||||
|
|
||||||
sockaddr* getPublicSocket() const { return _publicSocket; }
|
sockaddr* getPublicSocket() const { return _publicSocket; }
|
||||||
void setPublicSocket(sockaddr* publicSocket) { _publicSocket = publicSocket; }
|
void setPublicSocket(sockaddr* publicSocket) { _publicSocket = publicSocket; }
|
||||||
|
@ -71,8 +71,8 @@ private:
|
||||||
|
|
||||||
char _type;
|
char _type;
|
||||||
uint16_t _agentID;
|
uint16_t _agentID;
|
||||||
double _wakeMicrostamp;
|
long long _wakeMicrostamp;
|
||||||
double _lastHeardMicrostamp;
|
long long _lastHeardMicrostamp;
|
||||||
sockaddr* _publicSocket;
|
sockaddr* _publicSocket;
|
||||||
sockaddr* _localSocket;
|
sockaddr* _localSocket;
|
||||||
sockaddr* _activeSocket;
|
sockaddr* _activeSocket;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
const char SOLO_AGENT_TYPES[3] = {
|
const char SOLO_AGENT_TYPES[3] = {
|
||||||
AGENT_TYPE_AVATAR_MIXER,
|
AGENT_TYPE_AVATAR_MIXER,
|
||||||
AGENT_TYPE_AUDIO_MIXER,
|
AGENT_TYPE_AUDIO_MIXER,
|
||||||
AGENT_TYPE_VOXEL
|
AGENT_TYPE_VOXEL_SERVER
|
||||||
};
|
};
|
||||||
|
|
||||||
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
|
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
|
||||||
|
@ -34,7 +34,6 @@ char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup
|
||||||
const int DOMAINSERVER_PORT = 40102;
|
const int DOMAINSERVER_PORT = 40102;
|
||||||
|
|
||||||
bool silentAgentThreadStopFlag = false;
|
bool silentAgentThreadStopFlag = false;
|
||||||
bool domainServerCheckinStopFlag = false;
|
|
||||||
bool pingUnknownAgentThreadStopFlag = false;
|
bool pingUnknownAgentThreadStopFlag = false;
|
||||||
|
|
||||||
AgentList* AgentList::_sharedInstance = NULL;
|
AgentList* AgentList::_sharedInstance = NULL;
|
||||||
|
@ -60,27 +59,24 @@ AgentList* AgentList::getInstance() {
|
||||||
AgentList::AgentList(char newOwnerType, unsigned int newSocketListenPort) :
|
AgentList::AgentList(char newOwnerType, unsigned int newSocketListenPort) :
|
||||||
_agentBuckets(),
|
_agentBuckets(),
|
||||||
_numAgents(0),
|
_numAgents(0),
|
||||||
agentSocket(newSocketListenPort),
|
_agentSocket(newSocketListenPort),
|
||||||
_ownerType(newOwnerType),
|
_ownerType(newOwnerType),
|
||||||
socketListenPort(newSocketListenPort),
|
_agentTypesOfInterest(NULL),
|
||||||
_ownerID(UNKNOWN_AGENT_ID),
|
_ownerID(UNKNOWN_AGENT_ID),
|
||||||
_lastAgentID(0) {
|
_lastAgentID(0) {
|
||||||
pthread_mutex_init(&mutex, 0);
|
pthread_mutex_init(&mutex, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
AgentList::~AgentList() {
|
AgentList::~AgentList() {
|
||||||
|
delete _agentTypesOfInterest;
|
||||||
|
|
||||||
// stop the spawned threads, if they were started
|
// stop the spawned threads, if they were started
|
||||||
stopSilentAgentRemovalThread();
|
stopSilentAgentRemovalThread();
|
||||||
stopDomainServerCheckInThread();
|
|
||||||
stopPingUnknownAgentsThread();
|
stopPingUnknownAgentsThread();
|
||||||
|
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int AgentList::getSocketListenPort() {
|
|
||||||
return socketListenPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AgentList::processAgentData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) {
|
void AgentList::processAgentData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) {
|
||||||
switch (((char *)packetData)[0]) {
|
switch (((char *)packetData)[0]) {
|
||||||
case PACKET_HEADER_DOMAIN: {
|
case PACKET_HEADER_DOMAIN: {
|
||||||
|
@ -88,7 +84,7 @@ void AgentList::processAgentData(sockaddr *senderAddress, unsigned char *packetD
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PACKET_HEADER_PING: {
|
case PACKET_HEADER_PING: {
|
||||||
agentSocket.send(senderAddress, &PACKET_HEADER_PING_REPLY, 1);
|
_agentSocket.send(senderAddress, &PACKET_HEADER_PING_REPLY, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PACKET_HEADER_PING_REPLY: {
|
case PACKET_HEADER_PING_REPLY: {
|
||||||
|
@ -181,6 +177,72 @@ Agent* AgentList::agentWithID(uint16_t agentID) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AgentList::setAgentTypesOfInterest(const char* agentTypesOfInterest, int numAgentTypesOfInterest) {
|
||||||
|
delete _agentTypesOfInterest;
|
||||||
|
|
||||||
|
_agentTypesOfInterest = new 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;
|
||||||
|
static int checkInPacketSize;
|
||||||
|
|
||||||
|
if (!checkInPacket) {
|
||||||
|
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(unsigned char);
|
||||||
|
|
||||||
|
checkInPacket = new unsigned char[numPacketBytes];
|
||||||
|
unsigned char* packetPosition = checkInPacket;
|
||||||
|
|
||||||
|
*(packetPosition++) = (memchr(SOLO_AGENT_TYPES, _ownerType, sizeof(SOLO_AGENT_TYPES)))
|
||||||
|
? PACKET_HEADER_DOMAIN_REPORT_FOR_DUTY
|
||||||
|
: PACKET_HEADER_DOMAIN_LIST_REQUEST;
|
||||||
|
*(packetPosition++) = _ownerType;
|
||||||
|
|
||||||
|
packetPosition += packSocket(checkInPacket + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE),
|
||||||
|
getLocalAddress(),
|
||||||
|
htons(_agentSocket.getListeningPort()));
|
||||||
|
|
||||||
|
// add the number of bytes for agent types of interest
|
||||||
|
*(packetPosition++) = numBytesAgentsOfInterest;
|
||||||
|
|
||||||
|
// copy over the bytes for agent types of interest, if required
|
||||||
|
if (numBytesAgentsOfInterest > 0) {
|
||||||
|
memcpy(packetPosition,
|
||||||
|
_agentTypesOfInterest,
|
||||||
|
numBytesAgentsOfInterest);
|
||||||
|
packetPosition += numBytesAgentsOfInterest;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkInPacketSize = packetPosition - checkInPacket;
|
||||||
|
}
|
||||||
|
|
||||||
|
_agentSocket.send(DOMAIN_IP, DOMAINSERVER_PORT, checkInPacket, checkInPacketSize);
|
||||||
|
}
|
||||||
|
|
||||||
int AgentList::processDomainServerList(unsigned char *packetData, size_t dataBytes) {
|
int AgentList::processDomainServerList(unsigned char *packetData, size_t dataBytes) {
|
||||||
int readAgents = 0;
|
int readAgents = 0;
|
||||||
|
|
||||||
|
@ -233,7 +295,7 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket
|
||||||
newAgent->activatePublicSocket();
|
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_AVATAR_MIXER ||
|
||||||
newAgent->getType() == AGENT_TYPE_AUDIO_MIXER) {
|
newAgent->getType() == AGENT_TYPE_AUDIO_MIXER) {
|
||||||
// this is currently the cheat we use to talk directly to our test servers on EC2
|
// this is currently the cheat we use to talk directly to our test servers on EC2
|
||||||
|
@ -247,9 +309,7 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (agent->getType() == AGENT_TYPE_AUDIO_MIXER ||
|
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
|
// 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
|
// the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously
|
||||||
agent->setLastHeardMicrostamp(usecTimestampNow());
|
agent->setLastHeardMicrostamp(usecTimestampNow());
|
||||||
|
@ -281,7 +341,7 @@ void AgentList::broadcastToAgents(unsigned char *broadcastData, size_t dataBytes
|
||||||
// only send to the AgentTypes we are asked to send to.
|
// only send to the AgentTypes we are asked to send to.
|
||||||
if (agent->getActiveSocket() != NULL && memchr(agentTypes, agent->getType(), numAgentTypes)) {
|
if (agent->getActiveSocket() != NULL && memchr(agentTypes, agent->getType(), numAgentTypes)) {
|
||||||
// we know which socket is good for this agent, send there
|
// we know which socket is good for this agent, send there
|
||||||
agentSocket.send(agent->getActiveSocket(), broadcastData, dataBytes);
|
_agentSocket.send(agent->getActiveSocket(), broadcastData, dataBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,7 +393,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) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
|
@ -354,7 +414,7 @@ void AgentList::stopPingUnknownAgentsThread() {
|
||||||
|
|
||||||
void *removeSilentAgents(void *args) {
|
void *removeSilentAgents(void *args) {
|
||||||
AgentList* agentList = (AgentList*) args;
|
AgentList* agentList = (AgentList*) args;
|
||||||
double checkTimeUSecs, sleepTime;
|
long long checkTimeUSecs, sleepTime;
|
||||||
|
|
||||||
while (!silentAgentThreadStopFlag) {
|
while (!silentAgentThreadStopFlag) {
|
||||||
checkTimeUSecs = usecTimestampNow();
|
checkTimeUSecs = usecTimestampNow();
|
||||||
|
@ -362,8 +422,8 @@ void *removeSilentAgents(void *args) {
|
||||||
for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); ++agent) {
|
for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); ++agent) {
|
||||||
|
|
||||||
if ((checkTimeUSecs - agent->getLastHeardMicrostamp()) > AGENT_SILENCE_THRESHOLD_USECS
|
if ((checkTimeUSecs - agent->getLastHeardMicrostamp()) > AGENT_SILENCE_THRESHOLD_USECS
|
||||||
&& agent->getType() != AGENT_TYPE_VOXEL) {
|
&& agent->getType() != AGENT_TYPE_VOXEL_SERVER) {
|
||||||
|
|
||||||
printLog("Killed ");
|
printLog("Killed ");
|
||||||
Agent::printLog(*agent);
|
Agent::printLog(*agent);
|
||||||
|
|
||||||
|
@ -392,62 +452,6 @@ void AgentList::stopSilentAgentRemovalThread() {
|
||||||
pthread_join(removeSilentAgentsThread, NULL);
|
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 {
|
AgentList::iterator AgentList::begin() const {
|
||||||
Agent** agentBucket = NULL;
|
Agent** agentBucket = NULL;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,10 @@ const int AGENTS_PER_BUCKET = 100;
|
||||||
|
|
||||||
const int MAX_PACKET_SIZE = 1500;
|
const int MAX_PACKET_SIZE = 1500;
|
||||||
const unsigned int AGENT_SOCKET_LISTEN_PORT = 40103;
|
const unsigned int AGENT_SOCKET_LISTEN_PORT = 40103;
|
||||||
|
|
||||||
const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000;
|
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 const char SOLO_AGENT_TYPES[3];
|
||||||
|
|
||||||
extern char DOMAIN_HOSTNAME[];
|
extern char DOMAIN_HOSTNAME[];
|
||||||
|
@ -45,15 +48,27 @@ public:
|
||||||
AgentListIterator begin() const;
|
AgentListIterator begin() const;
|
||||||
AgentListIterator end() 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 _agentSocket.getListeningPort(); };
|
||||||
|
|
||||||
void(*linkedDataCreateCallback)(Agent *);
|
void(*linkedDataCreateCallback)(Agent *);
|
||||||
|
|
||||||
int size() { return _numAgents; }
|
int size() { return _numAgents; }
|
||||||
|
|
||||||
UDPSocket* getAgentSocket() { return &agentSocket; }
|
|
||||||
|
|
||||||
void lock() { pthread_mutex_lock(&mutex); }
|
void lock() { pthread_mutex_lock(&mutex); }
|
||||||
void unlock() { pthread_mutex_unlock(&mutex); }
|
void unlock() { pthread_mutex_unlock(&mutex); }
|
||||||
|
|
||||||
|
void setAgentTypesOfInterest(const char* agentTypesOfInterest, int numAgentTypesOfInterest);
|
||||||
|
void sendDomainServerCheckIn();
|
||||||
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
||||||
|
|
||||||
Agent* agentWithAddress(sockaddr *senderAddress);
|
Agent* agentWithAddress(sockaddr *senderAddress);
|
||||||
|
@ -68,22 +83,11 @@ public:
|
||||||
int updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes);
|
int updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes);
|
||||||
|
|
||||||
void broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes);
|
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; }
|
|
||||||
|
|
||||||
Agent* soloAgentOfType(char agentType);
|
Agent* soloAgentOfType(char agentType);
|
||||||
|
|
||||||
void startSilentAgentRemovalThread();
|
void startSilentAgentRemovalThread();
|
||||||
void stopSilentAgentRemovalThread();
|
void stopSilentAgentRemovalThread();
|
||||||
void startDomainServerCheckInThread();
|
|
||||||
void stopDomainServerCheckInThread();
|
|
||||||
void startPingUnknownAgentsThread();
|
void startPingUnknownAgentsThread();
|
||||||
void stopPingUnknownAgentsThread();
|
void stopPingUnknownAgentsThread();
|
||||||
|
|
||||||
|
@ -100,9 +104,10 @@ private:
|
||||||
|
|
||||||
Agent** _agentBuckets[MAX_NUM_AGENTS / AGENTS_PER_BUCKET];
|
Agent** _agentBuckets[MAX_NUM_AGENTS / AGENTS_PER_BUCKET];
|
||||||
int _numAgents;
|
int _numAgents;
|
||||||
UDPSocket agentSocket;
|
UDPSocket _agentSocket;
|
||||||
char _ownerType;
|
char _ownerType;
|
||||||
unsigned int socketListenPort;
|
char* _agentTypesOfInterest;
|
||||||
|
unsigned int _socketListenPort;
|
||||||
uint16_t _ownerID;
|
uint16_t _ownerID;
|
||||||
uint16_t _lastAgentID;
|
uint16_t _lastAgentID;
|
||||||
pthread_t removeSilentAgentsThread;
|
pthread_t removeSilentAgentsThread;
|
||||||
|
|
|
@ -3,11 +3,10 @@
|
||||||
// hifi
|
// hifi
|
||||||
//
|
//
|
||||||
// Created by Brad Hefta-Gaub on 2013/04/09
|
// 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.
|
// 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.
|
// For example, an agent whose is 'V' is always a voxel server.
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef hifi_AgentTypes_h
|
#ifndef hifi_AgentTypes_h
|
||||||
#define hifi_AgentTypes_h
|
#define hifi_AgentTypes_h
|
||||||
|
@ -17,13 +16,13 @@
|
||||||
// If you don't then it will make things harder on your co-developers in debugging because the Agent
|
// 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".
|
// class won't know the name and will report it as "Unknown".
|
||||||
|
|
||||||
// Agent Type Codes
|
typedef char AGENT_TYPE;
|
||||||
const char AGENT_TYPE_DOMAIN = 'D';
|
const AGENT_TYPE AGENT_TYPE_DOMAIN = 'D';
|
||||||
const char AGENT_TYPE_VOXEL = 'V';
|
const AGENT_TYPE AGENT_TYPE_VOXEL_SERVER = 'V';
|
||||||
const char AGENT_TYPE_AVATAR = 'I';
|
const AGENT_TYPE AGENT_TYPE_AVATAR = 'I';
|
||||||
const char AGENT_TYPE_AUDIO_MIXER = 'M';
|
const AGENT_TYPE AGENT_TYPE_AUDIO_MIXER = 'M';
|
||||||
const char AGENT_TYPE_AVATAR_MIXER = 'W';
|
const AGENT_TYPE AGENT_TYPE_AVATAR_MIXER = 'W';
|
||||||
const char AGENT_TYPE_AUDIO_INJECTOR = 'A';
|
const AGENT_TYPE AGENT_TYPE_AUDIO_INJECTOR = 'A';
|
||||||
const char AGENT_TYPE_ANIMATION_SERVER = 'a';
|
const AGENT_TYPE AGENT_TYPE_ANIMATION_SERVER = 'a';
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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_TRANSMITTER_DATA_V2 = 'T';
|
||||||
const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e';
|
const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e';
|
||||||
const PACKET_HEADER PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L';
|
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
|
// These are supported Z-Command
|
||||||
|
|
|
@ -104,7 +104,7 @@ int PerfStat::DumpStats(char** array) {
|
||||||
|
|
||||||
// Destructor handles recording all of our stats
|
// Destructor handles recording all of our stats
|
||||||
PerformanceWarning::~PerformanceWarning() {
|
PerformanceWarning::~PerformanceWarning() {
|
||||||
double end = usecTimestampNow();
|
long long end = usecTimestampNow();
|
||||||
double elapsedmsec = (end - _start) / 1000.0;
|
double elapsedmsec = (end - _start) / 1000.0;
|
||||||
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
|
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
|
||||||
if (elapsedmsec > 1000) {
|
if (elapsedmsec > 1000) {
|
||||||
|
|
|
@ -84,7 +84,7 @@ typedef std::map<std::string,PerfStatHistory,std::less<std::string> >::iterator
|
||||||
|
|
||||||
class PerformanceWarning {
|
class PerformanceWarning {
|
||||||
private:
|
private:
|
||||||
double _start;
|
long long _start;
|
||||||
const char* _message;
|
const char* _message;
|
||||||
bool _renderWarningsOn;
|
bool _renderWarningsOn;
|
||||||
bool _alwaysDisplay;
|
bool _alwaysDisplay;
|
||||||
|
|
|
@ -22,14 +22,14 @@
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
double usecTimestamp(timeval *time) {
|
long long usecTimestamp(timeval *time) {
|
||||||
return (time->tv_sec * 1000000.0 + time->tv_usec);
|
return (time->tv_sec * 1000000 + time->tv_usec);
|
||||||
}
|
}
|
||||||
|
|
||||||
double usecTimestampNow() {
|
long long usecTimestampNow() {
|
||||||
timeval now;
|
timeval now;
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
return (now.tv_sec * 1000000.0 + now.tv_usec);
|
return (now.tv_sec * 1000000 + now.tv_usec);
|
||||||
}
|
}
|
||||||
|
|
||||||
float randFloat () {
|
float randFloat () {
|
||||||
|
@ -102,12 +102,12 @@ void setAtBit(unsigned char& byte, int bitIndex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int getSemiNibbleAt(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) {
|
void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) {
|
||||||
//assert(value <= 3 && value >= 0);
|
//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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@ static const float DECIMETER = 0.1f;
|
||||||
static const float CENTIMETER = 0.01f;
|
static const float CENTIMETER = 0.01f;
|
||||||
static const float MILLIIMETER = 0.001f;
|
static const float MILLIIMETER = 0.001f;
|
||||||
|
|
||||||
double usecTimestamp(timeval *time);
|
long long usecTimestamp(timeval *time);
|
||||||
double usecTimestampNow();
|
long long usecTimestampNow();
|
||||||
|
|
||||||
float randFloat();
|
float randFloat();
|
||||||
int randIntInRange (int min, int max);
|
int randIntInRange (int min, int max);
|
||||||
|
|
|
@ -25,7 +25,7 @@ public:
|
||||||
float getAverageSampleValuePerSecond();
|
float getAverageSampleValuePerSecond();
|
||||||
private:
|
private:
|
||||||
int _numSamples;
|
int _numSamples;
|
||||||
double _lastEventTimestamp;
|
long long _lastEventTimestamp;
|
||||||
float _average;
|
float _average;
|
||||||
float _eventDeltaAverage;
|
float _eventDeltaAverage;
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ unsigned short loadBufferWithSocketInfo(char* addressBuffer, sockaddr* socket) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UDPSocket::UDPSocket(int listeningPort) : blocking(true) {
|
UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking(true) {
|
||||||
init();
|
init();
|
||||||
// create the socket
|
// create the socket
|
||||||
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
@ -140,6 +140,13 @@ UDPSocket::UDPSocket(int listeningPort) : blocking(true) {
|
||||||
return;
|
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
|
// set timeout on socket recieve to 0.5 seconds
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
tv.tv_sec = 0;
|
tv.tv_sec = 0;
|
||||||
|
|
|
@ -23,14 +23,16 @@ public:
|
||||||
UDPSocket(int listening_port);
|
UDPSocket(int listening_port);
|
||||||
~UDPSocket();
|
~UDPSocket();
|
||||||
bool init();
|
bool init();
|
||||||
|
int getListeningPort() const { return listeningPort; }
|
||||||
void setBlocking(bool blocking);
|
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(sockaddr* destAddress, const void* data, size_t byteLength) const;
|
||||||
int send(char* destAddress, int destPort, 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(void* receivedData, ssize_t* receivedBytes) const;
|
||||||
bool receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const;
|
bool receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const;
|
||||||
private:
|
private:
|
||||||
int handle;
|
int handle;
|
||||||
|
int listeningPort;
|
||||||
bool blocking;
|
bool blocking;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ private:
|
||||||
#endif
|
#endif
|
||||||
glBufferIndex _glBufferIndex;
|
glBufferIndex _glBufferIndex;
|
||||||
bool _isDirty;
|
bool _isDirty;
|
||||||
double _lastChanged;
|
long long _lastChanged;
|
||||||
bool _shouldRender;
|
bool _shouldRender;
|
||||||
bool _isStagedForDeletion;
|
bool _isStagedForDeletion;
|
||||||
AABox _box;
|
AABox _box;
|
||||||
|
@ -80,7 +80,7 @@ public:
|
||||||
void printDebugDetails(const char* label) const;
|
void printDebugDetails(const char* label) const;
|
||||||
bool isDirty() const { return _isDirty; };
|
bool isDirty() const { return _isDirty; };
|
||||||
void clearDirtyBit() { _isDirty = false; };
|
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 markWithChangedTime() { _lastChanged = usecTimestampNow(); };
|
||||||
void handleSubtreeChanged(VoxelTree* myTree);
|
void handleSubtreeChanged(VoxelTree* myTree);
|
||||||
|
|
||||||
|
@ -103,8 +103,8 @@ public:
|
||||||
void setColor(const nodeColor& color);
|
void setColor(const nodeColor& color);
|
||||||
const nodeColor& getTrueColor() const { return _trueColor; };
|
const nodeColor& getTrueColor() const { return _trueColor; };
|
||||||
const nodeColor& getColor() const { return _currentColor; };
|
const nodeColor& getColor() const { return _currentColor; };
|
||||||
void setDensity(const float density) { _density = density; };
|
void setDensity(float density) { _density = density; };
|
||||||
const float getDensity() const { return _density; };
|
float getDensity() const { return _density; };
|
||||||
#else
|
#else
|
||||||
void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ };
|
void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ };
|
||||||
void setFalseColored(bool isFalseColored) { /* no op */ };
|
void setFalseColored(bool isFalseColored) { /* no op */ };
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo";
|
const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo";
|
||||||
const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/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;
|
const int VOXEL_LISTEN_PORT = 40106;
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ void resInVoxelDistributor(AgentList* agentList,
|
||||||
bool searchReset = false;
|
bool searchReset = false;
|
||||||
int searchLoops = 0;
|
int searchLoops = 0;
|
||||||
int searchLevelWas = agentData->getMaxSearchLevel();
|
int searchLevelWas = agentData->getMaxSearchLevel();
|
||||||
double start = usecTimestampNow();
|
long long start = usecTimestampNow();
|
||||||
while (!searchReset && agentData->nodeBag.isEmpty()) {
|
while (!searchReset && agentData->nodeBag.isEmpty()) {
|
||||||
searchLoops++;
|
searchLoops++;
|
||||||
|
|
||||||
|
@ -137,19 +137,19 @@ void resInVoxelDistributor(AgentList* agentList,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
double end = usecTimestampNow();
|
long long end = usecTimestampNow();
|
||||||
double elapsedmsec = (end - start)/1000.0;
|
int elapsedmsec = (end - start)/1000;
|
||||||
if (elapsedmsec > 100) {
|
if (elapsedmsec > 100) {
|
||||||
if (elapsedmsec > 1000) {
|
if (elapsedmsec > 1000) {
|
||||||
double elapsedsec = (end - start)/1000000.0;
|
int elapsedsec = (end - start)/1000000;
|
||||||
printf("WARNING! searchForColoredNodes() took %lf seconds to identify %d nodes at level %d in %d loops\n",
|
printf("WARNING! searchForColoredNodes() took %d seconds to identify %d nodes at level %d in %d loops\n",
|
||||||
elapsedsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
|
elapsedsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
|
||||||
} else {
|
} 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);
|
elapsedmsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
|
||||||
}
|
}
|
||||||
} else if (::debugVoxelSending) {
|
} 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);
|
elapsedmsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +161,7 @@ void resInVoxelDistributor(AgentList* agentList,
|
||||||
int packetsSentThisInterval = 0;
|
int packetsSentThisInterval = 0;
|
||||||
int truePacketsSent = 0;
|
int truePacketsSent = 0;
|
||||||
int trueBytesSent = 0;
|
int trueBytesSent = 0;
|
||||||
double start = usecTimestampNow();
|
long long start = usecTimestampNow();
|
||||||
|
|
||||||
bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
|
bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
|
||||||
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
|
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
|
||||||
|
@ -206,19 +206,19 @@ void resInVoxelDistributor(AgentList* agentList,
|
||||||
trueBytesSent += envPacketLength;
|
trueBytesSent += envPacketLength;
|
||||||
truePacketsSent++;
|
truePacketsSent++;
|
||||||
}
|
}
|
||||||
double end = usecTimestampNow();
|
long long end = usecTimestampNow();
|
||||||
double elapsedmsec = (end - start)/1000.0;
|
int elapsedmsec = (end - start)/1000;
|
||||||
if (elapsedmsec > 100) {
|
if (elapsedmsec > 100) {
|
||||||
if (elapsedmsec > 1000) {
|
if (elapsedmsec > 1000) {
|
||||||
double elapsedsec = (end - start)/1000000.0;
|
int elapsedsec = (end - start)/1000000;
|
||||||
printf("WARNING! packetLoop() took %lf seconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n",
|
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());
|
elapsedsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count());
|
||||||
} else {
|
} 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());
|
elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count());
|
||||||
}
|
}
|
||||||
} else if (::debugVoxelSending) {
|
} 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());
|
elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +245,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
||||||
pthread_mutex_lock(&::treeLock);
|
pthread_mutex_lock(&::treeLock);
|
||||||
|
|
||||||
int maxLevelReached = 0;
|
int maxLevelReached = 0;
|
||||||
double start = usecTimestampNow();
|
long long start = usecTimestampNow();
|
||||||
|
|
||||||
// FOR NOW... agent tells us if it wants to receive only view frustum deltas
|
// FOR NOW... agent tells us if it wants to receive only view frustum deltas
|
||||||
bool wantDelta = agentData->getWantDelta();
|
bool wantDelta = agentData->getWantDelta();
|
||||||
|
@ -281,19 +281,19 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
double end = usecTimestampNow();
|
long long end = usecTimestampNow();
|
||||||
double elapsedmsec = (end - start)/1000.0;
|
int elapsedmsec = (end - start)/1000;
|
||||||
if (elapsedmsec > 100) {
|
if (elapsedmsec > 100) {
|
||||||
if (elapsedmsec > 1000) {
|
if (elapsedmsec > 1000) {
|
||||||
double elapsedsec = (end - start)/1000000.0;
|
int elapsedsec = (end - start)/1000000;
|
||||||
printf("WARNING! searchForColoredNodes() took %lf seconds to identify %d nodes at level %d\n",
|
printf("WARNING! searchForColoredNodes() took %d seconds to identify %d nodes at level %d\n",
|
||||||
elapsedsec, agentData->nodeBag.count(), maxLevelReached);
|
elapsedsec, agentData->nodeBag.count(), maxLevelReached);
|
||||||
} else {
|
} 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);
|
elapsedmsec, agentData->nodeBag.count(), maxLevelReached);
|
||||||
}
|
}
|
||||||
} else if (::debugVoxelSending) {
|
} 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);
|
elapsedmsec, agentData->nodeBag.count(), maxLevelReached);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
||||||
int packetsSentThisInterval = 0;
|
int packetsSentThisInterval = 0;
|
||||||
int truePacketsSent = 0;
|
int truePacketsSent = 0;
|
||||||
int trueBytesSent = 0;
|
int trueBytesSent = 0;
|
||||||
double start = usecTimestampNow();
|
long long start = usecTimestampNow();
|
||||||
|
|
||||||
bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
|
bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
|
||||||
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
|
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
|
||||||
|
@ -351,19 +351,19 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
||||||
truePacketsSent++;
|
truePacketsSent++;
|
||||||
}
|
}
|
||||||
|
|
||||||
double end = usecTimestampNow();
|
long long end = usecTimestampNow();
|
||||||
double elapsedmsec = (end - start)/1000.0;
|
int elapsedmsec = (end - start)/1000;
|
||||||
if (elapsedmsec > 100) {
|
if (elapsedmsec > 100) {
|
||||||
if (elapsedmsec > 1000) {
|
if (elapsedmsec > 1000) {
|
||||||
double elapsedsec = (end - start)/1000000.0;
|
int elapsedsec = (end - start)/1000000;
|
||||||
printf("WARNING! packetLoop() took %lf seconds to generate %d bytes in %d packets %d nodes still to send\n",
|
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());
|
elapsedsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count());
|
||||||
} else {
|
} 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());
|
elapsedmsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count());
|
||||||
}
|
}
|
||||||
} else if (::debugVoxelSending) {
|
} 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());
|
elapsedmsec, trueBytesSent, truePacketsSent, agentData->nodeBag.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,10 +380,10 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
||||||
pthread_mutex_unlock(&::treeLock);
|
pthread_mutex_unlock(&::treeLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
double lastPersistVoxels = 0;
|
long long lastPersistVoxels = 0;
|
||||||
void persistVoxelsWhenDirty() {
|
void persistVoxelsWhenDirty() {
|
||||||
double now = usecTimestampNow();
|
long long now = usecTimestampNow();
|
||||||
double sinceLastTime = (now - ::lastPersistVoxels) / 1000.0;
|
long long sinceLastTime = (now - ::lastPersistVoxels) / 1000;
|
||||||
|
|
||||||
// check the dirty bit and persist here...
|
// check the dirty bit and persist here...
|
||||||
if (::wantVoxelPersist && ::serverTree.isDirty() && sinceLastTime > VOXEL_PERSIST_INTERVAL) {
|
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
|
// 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) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
|
@ -450,7 +450,7 @@ int main(int argc, const char * argv[]) {
|
||||||
|
|
||||||
pthread_mutex_init(&::treeLock, NULL);
|
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);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
|
||||||
// Handle Local Domain testing with the --local command line
|
// Handle Local Domain testing with the --local command line
|
||||||
|
@ -464,7 +464,6 @@ int main(int argc, const char * argv[]) {
|
||||||
|
|
||||||
agentList->linkedDataCreateCallback = &attachVoxelAgentDataToAgent;
|
agentList->linkedDataCreateCallback = &attachVoxelAgentDataToAgent;
|
||||||
agentList->startSilentAgentRemovalThread();
|
agentList->startSilentAgentRemovalThread();
|
||||||
agentList->startDomainServerCheckInThread();
|
|
||||||
|
|
||||||
srand((unsigned)time(0));
|
srand((unsigned)time(0));
|
||||||
|
|
||||||
|
@ -576,10 +575,19 @@ int main(int argc, const char * argv[]) {
|
||||||
|
|
||||||
unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE];
|
unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||||
ssize_t receivedBytes;
|
ssize_t receivedBytes;
|
||||||
|
|
||||||
|
timeval lastDomainServerCheckIn = {};
|
||||||
|
|
||||||
// loop to send to agents requesting data
|
// 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
|
// check to see if we need to persist our voxel state
|
||||||
persistVoxelsWhenDirty();
|
persistVoxelsWhenDirty();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue