mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 14:08:51 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into view_frustum_work
This commit is contained in:
commit
0bec7156aa
31 changed files with 982 additions and 839 deletions
|
@ -133,7 +133,7 @@ int main(int argc, const char * argv[])
|
|||
|
||||
if (DEBUG_TO_SELF ||
|
||||
!agent->matches((sockaddr *)&agentPublicAddress, (sockaddr *)&agentLocalAddress, agentType)) {
|
||||
if (memchr(SOLO_AGENT_TYPES_STRING, agent->getType(), 1) == NULL) {
|
||||
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) {
|
||||
|
|
|
@ -13,20 +13,31 @@
|
|||
#include <PacketHeaders.h>
|
||||
#include <AgentList.h>
|
||||
#include <AvatarData.h>
|
||||
#include <AudioInjector.h>
|
||||
|
||||
const int EVE_AGENT_LIST_PORT = 55441;
|
||||
const float DATA_SEND_INTERVAL_MSECS = 10;
|
||||
const int EVE_AGENT_LISTEN_PORT = 55441;
|
||||
|
||||
const float RANDOM_POSITION_MAX_DIMENSION = 5.0f;
|
||||
|
||||
const float DATA_SEND_INTERVAL_MSECS = 15;
|
||||
const float MIN_AUDIO_SEND_INTERVAL_SECS = 10;
|
||||
const int MIN_ITERATIONS_BETWEEN_AUDIO_SENDS = (MIN_AUDIO_SEND_INTERVAL_SECS * 1000) / DATA_SEND_INTERVAL_MSECS;
|
||||
const int MAX_AUDIO_SEND_INTERVAL_SECS = 15;
|
||||
const float MAX_ITERATIONS_BETWEEN_AUDIO_SENDS = (MAX_AUDIO_SEND_INTERVAL_SECS * 1000) / DATA_SEND_INTERVAL_MSECS;
|
||||
|
||||
bool stopReceiveAgentDataThread;
|
||||
bool injectAudioThreadRunning = false;
|
||||
|
||||
void *receiveAgentData(void *args)
|
||||
{
|
||||
int TEMP_AUDIO_LISTEN_PORT = 55439;
|
||||
// UDPSocket audioSocket(TEMP_AUDIO_LISTEN_PORT);
|
||||
|
||||
void *receiveAgentData(void *args) {
|
||||
sockaddr senderAddress;
|
||||
ssize_t bytesReceived;
|
||||
unsigned char incomingPacket[MAX_PACKET_SIZE];
|
||||
|
||||
AgentList *agentList = AgentList::getInstance();
|
||||
Agent *avatarMixer = NULL;
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
Agent* avatarMixer = NULL;
|
||||
|
||||
while (!::stopReceiveAgentDataThread) {
|
||||
if (agentList->getAgentSocket().receive(&senderAddress, incomingPacket, &bytesReceived)) {
|
||||
|
@ -54,9 +65,35 @@ void *receiveAgentData(void *args)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
void *injectAudio(void *args) {
|
||||
::injectAudioThreadRunning = true;
|
||||
|
||||
AudioInjector* eveAudioInjector = (AudioInjector *)args;
|
||||
|
||||
// look for an audio mixer in our agent list
|
||||
Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER);
|
||||
|
||||
if (audioMixer != NULL) {
|
||||
// until the audio mixer is setup for ping-reply, activate the public socket if it's not active
|
||||
if (audioMixer->getActiveSocket() == NULL) {
|
||||
audioMixer->activatePublicSocket();
|
||||
}
|
||||
|
||||
// we have an active audio mixer we can send data to
|
||||
// eveAudioInjector->injectAudio(&::audioSocket, audioMixer->getActiveSocket());
|
||||
}
|
||||
|
||||
::injectAudioThreadRunning = false;
|
||||
pthread_exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
// new seed for random audio sleep times
|
||||
srand(time(0));
|
||||
|
||||
// create an AgentList instance to handle communication with other agents
|
||||
AgentList *agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LIST_PORT);
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AVATAR, EVE_AGENT_LISTEN_PORT);
|
||||
|
||||
// start telling the domain server that we are alive
|
||||
agentList->startDomainServerCheckInThread();
|
||||
|
@ -74,15 +111,21 @@ int main(int argc, char* argv[]) {
|
|||
AvatarData eve = AvatarData();
|
||||
|
||||
// move eve away from the origin
|
||||
eve.setBodyPosition(glm::vec3(3, 0, -3));
|
||||
// pick a random point inside a 10x10 grid
|
||||
|
||||
// turn her back towards the origin
|
||||
eve.setBodyYaw(-45);
|
||||
eve.setPosition(glm::vec3(randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION),
|
||||
0,
|
||||
randFloatInRange(-RANDOM_POSITION_MAX_DIMENSION, RANDOM_POSITION_MAX_DIMENSION)));
|
||||
|
||||
// face any instance of eve down the z-axis
|
||||
eve.setBodyYaw(0);
|
||||
|
||||
// put her hand out so somebody can shake it
|
||||
eve.setHandPosition(glm::vec3(eve.getBodyPosition()[0] - 0.2,
|
||||
eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2,
|
||||
0.25,
|
||||
eve.getBodyPosition()[2] + 0.1));
|
||||
eve.getPosition()[2] + 0.1));
|
||||
// read eve's audio data
|
||||
AudioInjector eveAudioInjector("eve.raw");
|
||||
|
||||
unsigned char broadcastPacket[MAX_PACKET_SIZE];
|
||||
broadcastPacket[0] = PACKET_HEADER_HEAD_DATA;
|
||||
|
@ -92,6 +135,11 @@ int main(int argc, char* argv[]) {
|
|||
timeval thisSend;
|
||||
double numMicrosecondsSleep = 0;
|
||||
|
||||
// int numIterationsLeftBeforeAudioSend = 0;
|
||||
// pthread_t injectAudioThread;
|
||||
|
||||
int handStateTimer = 0;
|
||||
|
||||
while (true) {
|
||||
// update the thisSend timeval to the current time
|
||||
gettimeofday(&thisSend, NULL);
|
||||
|
@ -104,15 +152,38 @@ int main(int argc, char* argv[]) {
|
|||
// use the getBroadcastData method in the AvatarData class to populate the broadcastPacket buffer
|
||||
numBytesToSend = eve.getBroadcastData((broadcastPacket + 1));
|
||||
|
||||
|
||||
// use the UDPSocket instance attached to our agent list to send avatar data to mixer
|
||||
agentList->getAgentSocket().send(avatarMixer->getActiveSocket(), broadcastPacket, numBytesToSend);
|
||||
}
|
||||
|
||||
// temporarily disable Eve's audio sending until the file is actually available on EC2 box
|
||||
// if (numIterationsLeftBeforeAudioSend == 0) {
|
||||
// if (!::injectAudioThreadRunning) {
|
||||
// pthread_create(&injectAudioThread, NULL, injectAudio, (void*) &eveAudioInjector);
|
||||
//
|
||||
// numIterationsLeftBeforeAudioSend = randIntInRange(MIN_ITERATIONS_BETWEEN_AUDIO_SENDS,
|
||||
// MAX_ITERATIONS_BETWEEN_AUDIO_SENDS);
|
||||
// }
|
||||
// } else {
|
||||
// numIterationsLeftBeforeAudioSend--;
|
||||
// }
|
||||
|
||||
// sleep for the correct amount of time to have data send be consistently timed
|
||||
if ((numMicrosecondsSleep = (DATA_SEND_INTERVAL_MSECS * 1000) - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) {
|
||||
usleep(numMicrosecondsSleep);
|
||||
}
|
||||
|
||||
// simulate the effect of pressing and un-pressing the mouse button/pad
|
||||
handStateTimer++;
|
||||
if ( handStateTimer == 100 ) {
|
||||
eve.setHandState(1);
|
||||
}
|
||||
if ( handStateTimer == 150 ) {
|
||||
eve.setHandState(0);
|
||||
}
|
||||
if ( handStateTimer >= 200 ) {
|
||||
handStateTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// stop the receive agent data thread
|
||||
|
|
|
@ -14,4 +14,4 @@ link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
|||
|
||||
# link the threads library
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(injector ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT})
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// injector.cpp
|
||||
// main.cpp
|
||||
// Audio Injector
|
||||
//
|
||||
// Created by Leonardo Murillo on 3/5/13.
|
||||
|
@ -11,39 +11,27 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
#include "UDPSocket.h"
|
||||
#include "UDPSocket.cpp"
|
||||
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
||||
#include <UDPSocket.h>
|
||||
#include <AudioInjector.h>
|
||||
|
||||
char EC2_WEST_AUDIO_SERVER[] = "54.241.92.53";
|
||||
const int AUDIO_UDP_LISTEN_PORT = 55443;
|
||||
const int BUFFER_LENGTH_BYTES = 512;
|
||||
const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t);
|
||||
const float SAMPLE_RATE = 22050.0;
|
||||
const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000;
|
||||
|
||||
// Command line parameter defaults
|
||||
bool loopAudio = true;
|
||||
float sleepIntervalMin = 1.00;
|
||||
float sleepIntervalMax = 2.00;
|
||||
float positionInUniverse[] = {0, 0, 0, 0};
|
||||
unsigned char attenuationModifier = 255;
|
||||
char *sourceAudioFile;
|
||||
char *sourceAudioFile = NULL;
|
||||
const char *allowedParameters = ":rb::t::c::a::f:";
|
||||
|
||||
char *charBuffer;
|
||||
int16_t *buffer;
|
||||
long length;
|
||||
|
||||
UDPSocket *streamSocket;
|
||||
float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
unsigned char attenuationModifier = 255;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
|
@ -54,7 +42,7 @@ void usage(void)
|
|||
std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl;
|
||||
std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl;
|
||||
std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl;
|
||||
};
|
||||
}
|
||||
|
||||
bool processParameters(int parameterCount, char* parameterData[])
|
||||
{
|
||||
|
@ -62,19 +50,19 @@ bool processParameters(int parameterCount, char* parameterData[])
|
|||
while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) {
|
||||
switch (p) {
|
||||
case 'r':
|
||||
loopAudio = false;
|
||||
::loopAudio = false;
|
||||
std::cout << "[DEBUG] Random sleep mode enabled" << std::endl;
|
||||
break;
|
||||
case 'b':
|
||||
sleepIntervalMin = atof(optarg);
|
||||
::sleepIntervalMin = atof(optarg);
|
||||
std::cout << "[DEBUG] Min delay between plays " << sleepIntervalMin << "sec" << std::endl;
|
||||
break;
|
||||
case 't':
|
||||
sleepIntervalMax = atof(optarg);
|
||||
::sleepIntervalMax = atof(optarg);
|
||||
std::cout << "[DEBUG] Max delay between plays " << sleepIntervalMax << "sec" << std::endl;
|
||||
break;
|
||||
case 'f':
|
||||
sourceAudioFile = optarg;
|
||||
::sourceAudioFile = optarg;
|
||||
std::cout << "[DEBUG] Opening file: " << sourceAudioFile << std::endl;
|
||||
break;
|
||||
case 'c':
|
||||
|
@ -84,7 +72,7 @@ bool processParameters(int parameterCount, char* parameterData[])
|
|||
|
||||
int i = 0;
|
||||
while (std::getline(ss, token, ',')) {
|
||||
positionInUniverse[i] = atof(token.c_str());
|
||||
::floatArguments[i] = atof(token.c_str());
|
||||
++i;
|
||||
if (i == 4) {
|
||||
break;
|
||||
|
@ -94,7 +82,7 @@ bool processParameters(int parameterCount, char* parameterData[])
|
|||
break;
|
||||
}
|
||||
case 'a':
|
||||
attenuationModifier = atoi(optarg);
|
||||
::attenuationModifier = atoi(optarg);
|
||||
std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl;
|
||||
break;
|
||||
default:
|
||||
|
@ -105,78 +93,43 @@ bool processParameters(int parameterCount, char* parameterData[])
|
|||
return true;
|
||||
};
|
||||
|
||||
void loadFile(void) {
|
||||
std::fstream sourceFile;
|
||||
sourceFile.open(sourceAudioFile, std::ios::in | std::ios::binary);
|
||||
sourceFile.seekg(0, std::ios::end);
|
||||
length = sourceFile.tellg();
|
||||
sourceFile.seekg(0, std::ios::beg);
|
||||
long sizeOfShortArray = length / 2;
|
||||
buffer = new int16_t[sizeOfShortArray];
|
||||
sourceFile.read((char *)buffer, length);
|
||||
}
|
||||
|
||||
void stream(void)
|
||||
{
|
||||
timeval startTime;
|
||||
|
||||
int leadingBytes = 1 + (sizeof(float) * 4);
|
||||
unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes];
|
||||
|
||||
dataPacket[0] = PACKET_HEADER_INJECT_AUDIO;
|
||||
unsigned char *currentPacketPtr = dataPacket + 1;
|
||||
|
||||
for (int p = 0; p < 4; p++) {
|
||||
memcpy(currentPacketPtr, &positionInUniverse[p], sizeof(float));
|
||||
currentPacketPtr += sizeof(float);
|
||||
}
|
||||
|
||||
*currentPacketPtr = attenuationModifier;
|
||||
currentPacketPtr++;
|
||||
|
||||
for (int i = 0; i < length; i += BUFFER_LENGTH_SAMPLES) {
|
||||
gettimeofday(&startTime, NULL);
|
||||
memcpy(currentPacketPtr, &buffer[i], BUFFER_LENGTH_BYTES);
|
||||
streamSocket->send(EC2_WEST_AUDIO_SERVER, AUDIO_UDP_LISTEN_PORT, dataPacket, sizeof(dataPacket));
|
||||
double usecToSleep = usecTimestamp(&startTime) + BUFFER_SEND_INTERVAL_USECS - usecTimestampNow();
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
srand(time(0));
|
||||
int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1));
|
||||
|
||||
streamSocket = new UDPSocket(AUDIO_UDP_SEND_PORT);
|
||||
UDPSocket streamSocket(AUDIO_UDP_SEND_PORT);
|
||||
|
||||
sockaddr_in mixerSocket;
|
||||
mixerSocket.sin_family = AF_INET;
|
||||
mixerSocket.sin_addr.s_addr = inet_addr(EC2_WEST_AUDIO_SERVER);
|
||||
mixerSocket.sin_port = htons((uint16_t)AUDIO_UDP_LISTEN_PORT);
|
||||
|
||||
if (processParameters(argc, argv)) {
|
||||
if (sourceAudioFile) {
|
||||
loadFile();
|
||||
} else {
|
||||
if (::sourceAudioFile == NULL) {
|
||||
std::cout << "[FATAL] Source audio file not specified" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(positionInUniverse)/sizeof(positionInUniverse[0]); ++i) {
|
||||
std::cout << "Position " << positionInUniverse[i] << std::endl;
|
||||
}
|
||||
|
||||
float delay;
|
||||
int usecDelay;
|
||||
while (true) {
|
||||
stream();
|
||||
|
||||
if (loopAudio) {
|
||||
delay = 0;
|
||||
} else {
|
||||
delay = randFloatInRange(sleepIntervalMin, sleepIntervalMax);
|
||||
}
|
||||
AudioInjector injector(sourceAudioFile);
|
||||
|
||||
injector.setPosition(::floatArguments);
|
||||
injector.setBearing(*(::floatArguments + 3));
|
||||
injector.setAttenuationModifier(::attenuationModifier);
|
||||
|
||||
float delay = 0;
|
||||
int usecDelay = 0;
|
||||
|
||||
while (true) {
|
||||
injector.injectAudio(&streamSocket, (sockaddr*) &mixerSocket);
|
||||
|
||||
if (!::loopAudio) {
|
||||
delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax);
|
||||
usecDelay = delay * 1000 * 1000;
|
||||
usleep(usecDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -130,7 +130,7 @@ int audioCallback (const void *inputBuffer,
|
|||
|
||||
loudness /= BUFFER_LENGTH_SAMPLES;
|
||||
data->lastInputLoudness = loudness;
|
||||
data->averagedInputLoudness = 0.66*data->averagedInputLoudness + 0.33*loudness;
|
||||
|
||||
//
|
||||
// If scope is turned on, copy input buffer to scope
|
||||
//
|
||||
|
@ -157,7 +157,7 @@ int audioCallback (const void *inputBuffer,
|
|||
|
||||
// memcpy the three float positions
|
||||
for (int p = 0; p < 3; p++) {
|
||||
memcpy(currentPacketPtr, &data->linkedHead->getBodyPosition()[p], sizeof(float));
|
||||
memcpy(currentPacketPtr, &data->linkedAvatar->getPosition()[p], sizeof(float));
|
||||
currentPacketPtr += sizeof(float);
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ int audioCallback (const void *inputBuffer,
|
|||
*(currentPacketPtr++) = 255;
|
||||
|
||||
// memcpy the corrected render yaw
|
||||
float correctedYaw = fmodf(data->linkedHead->getRenderYaw(), 360);
|
||||
float correctedYaw = fmodf(data->linkedAvatar->getRenderYaw(), 360);
|
||||
|
||||
if (correctedYaw > 180) {
|
||||
correctedYaw -= 360;
|
||||
|
@ -259,7 +259,7 @@ int audioCallback (const void *inputBuffer,
|
|||
// rotation of the head relative to body, this may effect flange effect!
|
||||
//
|
||||
//
|
||||
int lastYawMeasured = fabsf(data->linkedHead->getLastMeasuredHeadYaw());
|
||||
int lastYawMeasured = fabsf(data->linkedAvatar->getLastMeasuredHeadYaw());
|
||||
|
||||
if (!samplesLeftForFlange && lastYawMeasured > MIN_FLANGE_EFFECT_THRESHOLD) {
|
||||
// we should flange for one second
|
||||
|
@ -448,7 +448,7 @@ void Audio::setWalkingState(bool newWalkState) {
|
|||
* @return Returns true if successful or false if an error occurred.
|
||||
Use Audio::getError() to retrieve the error code.
|
||||
*/
|
||||
Audio::Audio(Oscilloscope *s, Head *linkedHead)
|
||||
Audio::Audio(Oscilloscope *s, Avatar *linkedAvatar)
|
||||
{
|
||||
// read the walking sound from the raw file and store it
|
||||
// in the in memory array
|
||||
|
@ -472,7 +472,7 @@ Audio::Audio(Oscilloscope *s, Head *linkedHead)
|
|||
|
||||
audioData = new AudioData();
|
||||
|
||||
audioData->linkedHead = linkedHead;
|
||||
audioData->linkedAvatar = linkedAvatar;
|
||||
|
||||
// setup a UDPSocket
|
||||
audioData->audioSocket = new UDPSocket(AUDIO_UDP_LISTEN_PORT);
|
||||
|
@ -510,9 +510,8 @@ error:
|
|||
}
|
||||
|
||||
|
||||
void Audio::getInputLoudness(float * lastLoudness, float * averageLoudness) {
|
||||
*lastLoudness = audioData->lastInputLoudness;
|
||||
*averageLoudness = audioData->averagedInputLoudness;
|
||||
float Audio::getInputLoudness() const {
|
||||
return audioData->lastInputLoudness;
|
||||
}
|
||||
|
||||
void Audio::render(int screenWidth, int screenHeight)
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
#include <portaudio.h>
|
||||
#include "AudioData.h"
|
||||
#include "Oscilloscope.h"
|
||||
#include "Head.h"
|
||||
#include "Avatar.h"
|
||||
|
||||
class Audio {
|
||||
public:
|
||||
// initializes audio I/O
|
||||
Audio(Oscilloscope *s, Head *linkedHead);
|
||||
Audio(Oscilloscope *s, Avatar *linkedAvatar);
|
||||
|
||||
void render();
|
||||
void render(int screenWidth, int screenHeight);
|
||||
|
@ -25,7 +25,7 @@ public:
|
|||
bool getMixerLoopbackFlag();
|
||||
void setMixerLoopbackFlag(bool newMixerLoopbackFlag);
|
||||
|
||||
void getInputLoudness(float * lastLoudness, float * averageLoudness);
|
||||
float getInputLoudness() const;
|
||||
void updateMixerParams(in_addr_t mixerAddress, in_port_t mixerPort);
|
||||
|
||||
void setWalkingState(bool newWalkState);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include "AudioRingBuffer.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Head.h"
|
||||
#include "Avatar.h"
|
||||
|
||||
class AudioData {
|
||||
public:
|
||||
|
@ -23,7 +23,7 @@ class AudioData {
|
|||
|
||||
UDPSocket *audioSocket;
|
||||
|
||||
Head *linkedHead;
|
||||
Avatar *linkedAvatar;
|
||||
|
||||
// store current mixer address and port
|
||||
in_addr_t mixerAddress;
|
||||
|
@ -36,7 +36,6 @@ class AudioData {
|
|||
int wasStarved;
|
||||
|
||||
float lastInputLoudness;
|
||||
float averagedInputLoudness;
|
||||
|
||||
bool mixerLoopbackFlag;
|
||||
bool playWalkSound;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Head.cpp
|
||||
// Avatar.cpp
|
||||
// interface
|
||||
//
|
||||
// Created by Philip Rosedale on 9/11/12.
|
||||
|
@ -11,7 +11,7 @@
|
|||
#include <vector>
|
||||
#include <lodepng.h>
|
||||
#include <SharedUtil.h>
|
||||
#include "Head.h"
|
||||
#include "Avatar.h"
|
||||
#include "Log.h"
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
|
@ -35,22 +35,19 @@ float browThickness = 0.16;
|
|||
|
||||
bool usingBigSphereCollisionTest = true;
|
||||
|
||||
|
||||
|
||||
char iris_texture_file[] = "resources/images/green_eye.png";
|
||||
|
||||
vector<unsigned char> iris_texture;
|
||||
unsigned int iris_texture_width = 512;
|
||||
unsigned int iris_texture_height = 256;
|
||||
|
||||
Head::Head(bool isMine) {
|
||||
Avatar::Avatar(bool isMine) {
|
||||
|
||||
_orientation.setToIdentity();
|
||||
|
||||
_velocity = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_thrust = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_rotation = glm::quat( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
_closestOtherAvatar = 0;
|
||||
_bodyYaw = -90.0;
|
||||
_bodyPitch = 0.0;
|
||||
_bodyRoll = 0.0;
|
||||
|
@ -62,7 +59,6 @@ Head::Head(bool isMine) {
|
|||
//_transmitterTimer = 0;
|
||||
_transmitterHz = 0.0;
|
||||
_transmitterPackets = 0;
|
||||
_numOtherAvatarsInView = 0;
|
||||
|
||||
initializeSkeleton();
|
||||
|
||||
|
@ -75,9 +71,6 @@ Head::Head(bool isMine) {
|
|||
_head.interPupilDistance = 0.6;
|
||||
_head.interBrowDistance = 0.75;
|
||||
_head.nominalPupilSize = 0.10;
|
||||
//_head.yaw = 0.0;
|
||||
//_head.pitch = 0.0;
|
||||
//_head.roll = 0.0;
|
||||
_head.pitchRate = 0.0;
|
||||
_head.yawRate = 0.0;
|
||||
_head.rollRate = 0.0;
|
||||
|
@ -110,15 +103,19 @@ Head::Head(bool isMine) {
|
|||
_head.lastLoudness = 0.0;
|
||||
_head.browAudioLift = 0.0;
|
||||
_head.noise = 0;
|
||||
|
||||
_movedHandOffset = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_usingBodySprings = true;
|
||||
_springForce = 6.0f;
|
||||
_springVelocityDecay = 16.0f;
|
||||
_renderYaw = 0.0;
|
||||
_renderPitch = 0.0;
|
||||
|
||||
_sphere = NULL;
|
||||
_interactingOther = NULL;
|
||||
_interactingOtherIsNearby = false;
|
||||
|
||||
_handHolding.position = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
_handHolding.force = 10.0f;
|
||||
|
||||
if (iris_texture.size() == 0) {
|
||||
switchToResourcesParentIfRequired();
|
||||
|
@ -127,23 +124,16 @@ Head::Head(bool isMine) {
|
|||
printLog("error %u: %s\n", error, lodepng_error_text(error));
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// test... just slam them into random positions...
|
||||
//--------------------------------------------------
|
||||
_otherAvatarHandPosition[ 0 ] = glm::vec3( 0.0f, 0.3f, 2.0f );
|
||||
_otherAvatarHandPosition[ 1 ] = glm::vec3( 4.0f, 0.3f, 2.0f );
|
||||
_otherAvatarHandPosition[ 2 ] = glm::vec3( 2.0f, 0.3f, 2.0f );
|
||||
_otherAvatarHandPosition[ 3 ] = glm::vec3( 1.0f, 0.3f, -4.0f );
|
||||
_otherAvatarHandPosition[ 4 ] = glm::vec3( -2.0f, 0.3f, -2.0f );
|
||||
}
|
||||
|
||||
Head::Head(const Head &otherAvatar) {
|
||||
|
||||
|
||||
Avatar::Avatar(const Avatar &otherAvatar) {
|
||||
|
||||
_velocity = otherAvatar._velocity;
|
||||
_thrust = otherAvatar._thrust;
|
||||
_rotation = otherAvatar._rotation;
|
||||
_closestOtherAvatar = otherAvatar._closestOtherAvatar;
|
||||
_interactingOtherIsNearby = otherAvatar._interactingOtherIsNearby;
|
||||
_bodyYaw = otherAvatar._bodyYaw;
|
||||
_bodyPitch = otherAvatar._bodyPitch;
|
||||
_bodyRoll = otherAvatar._bodyRoll;
|
||||
|
@ -175,9 +165,6 @@ Head::Head(const Head &otherAvatar) {
|
|||
_head.interPupilDistance = otherAvatar._head.interPupilDistance;
|
||||
_head.interBrowDistance = otherAvatar._head.interBrowDistance;
|
||||
_head.nominalPupilSize = otherAvatar._head.nominalPupilSize;
|
||||
//_head.yaw = otherAvatar._head.yaw;
|
||||
//_head.pitch = otherAvatar._head.pitch;
|
||||
//_head.roll = otherAvatar._head.roll;
|
||||
_head.yawRate = otherAvatar._head.yawRate;
|
||||
_head.pitchRate = otherAvatar._head.pitchRate;
|
||||
_head.rollRate = otherAvatar._head.rollRate;
|
||||
|
@ -211,7 +198,6 @@ Head::Head(const Head &otherAvatar) {
|
|||
_head.browAudioLift = otherAvatar._head.browAudioLift;
|
||||
_head.noise = otherAvatar._head.noise;
|
||||
|
||||
|
||||
if (iris_texture.size() == 0) {
|
||||
switchToResourcesParentIfRequired();
|
||||
unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file);
|
||||
|
@ -221,25 +207,24 @@ Head::Head(const Head &otherAvatar) {
|
|||
}
|
||||
}
|
||||
|
||||
Head::~Head() {
|
||||
Avatar::~Avatar() {
|
||||
if (_sphere != NULL) {
|
||||
gluDeleteQuadric(_sphere);
|
||||
}
|
||||
}
|
||||
|
||||
Head* Head::clone() const {
|
||||
return new Head(*this);
|
||||
Avatar* Avatar::clone() const {
|
||||
return new Avatar(*this);
|
||||
}
|
||||
|
||||
void Head::reset() {
|
||||
void Avatar::reset() {
|
||||
_headPitch = _headYaw = _headRoll = 0;
|
||||
_head.leanForward = _head.leanSideways = 0;
|
||||
}
|
||||
|
||||
|
||||
//this pertains to moving the head with the glasses
|
||||
//---------------------------------------------------
|
||||
void Head::UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity)
|
||||
void Avatar::UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity)
|
||||
// Using serial data, update avatar/render position and angles
|
||||
{
|
||||
const float PITCH_ACCEL_COUPLING = 0.5;
|
||||
|
@ -278,129 +263,137 @@ void Head::UpdateGyros(float frametime, SerialInterface * serialInterface, glm::
|
|||
addLean(-measured_lateral_accel * frametime * HEAD_LEAN_SCALE, -measured_fwd_accel*frametime * HEAD_LEAN_SCALE);
|
||||
}
|
||||
|
||||
void Head::addLean(float x, float z) {
|
||||
void Avatar::addLean(float x, float z) {
|
||||
// Add Body lean as impulse
|
||||
_head.leanSideways += x;
|
||||
_head.leanForward += z;
|
||||
}
|
||||
|
||||
|
||||
void Head::setLeanForward(float dist){
|
||||
void Avatar::setLeanForward(float dist){
|
||||
_head.leanForward = dist;
|
||||
}
|
||||
|
||||
void Head::setLeanSideways(float dist){
|
||||
void Avatar::setLeanSideways(float dist){
|
||||
_head.leanSideways = dist;
|
||||
}
|
||||
|
||||
void Head::setMousePressed( bool d ) {
|
||||
void Avatar::setMousePressed( bool d ) {
|
||||
_mousePressed = d;
|
||||
}
|
||||
|
||||
void Avatar::simulate(float deltaTime) {
|
||||
|
||||
void Head::simulate(float deltaTime) {
|
||||
// update avatar skeleton
|
||||
updateSkeleton();
|
||||
|
||||
// reset hand and arm positions according to hand movement
|
||||
updateHandMovement( deltaTime );
|
||||
|
||||
if ( !_interactingOtherIsNearby ) {
|
||||
//initialize _handHolding
|
||||
_handHolding.position = _bone[ AVATAR_BONE_RIGHT_HAND ].position;
|
||||
_handHolding.velocity = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
}
|
||||
|
||||
_interactingOtherIsNearby = false;
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// if the avatar being simulated is mine, then loop through
|
||||
// all the other avatars to get information about them...
|
||||
//-------------------------------------------------------------
|
||||
// all the other avatars for potential interactions...
|
||||
if ( _isMine )
|
||||
{
|
||||
//-------------------------------------
|
||||
// DEBUG - other avatars...
|
||||
//-------------------------------------
|
||||
_closestOtherAvatar = -1;
|
||||
float closestDistance = 10000.0f;
|
||||
|
||||
AgentList * agentList = AgentList::getInstance();
|
||||
|
||||
_numOtherAvatarsInView =0;
|
||||
|
||||
for(std::vector<Agent>::iterator agent = agentList->getAgents().begin();
|
||||
agent != agentList->getAgents().end();
|
||||
agent++) {
|
||||
if (( agent->getLinkedData() != NULL && ( agent->getType() == AGENT_TYPE_AVATAR ) )) {
|
||||
Head *otherAvatar = (Head *)agent->getLinkedData();
|
||||
Avatar *otherAvatar = (Avatar *)agent->getLinkedData();
|
||||
|
||||
if ( _numOtherAvatarsInView < MAX_OTHER_AVATARS ) {
|
||||
// check for collisions with other avatars and respond
|
||||
updateAvatarCollisionDetectionAndResponse
|
||||
(
|
||||
otherAvatar->getBonePosition( AVATAR_BONE_PELVIS_SPINE ),
|
||||
0.2,
|
||||
0.2,
|
||||
otherAvatar->getBodyUpDirection(),
|
||||
deltaTime
|
||||
);
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// test other avatar hand position for proximity...
|
||||
//-----------------------------------------------------------
|
||||
_otherAvatarHandPosition[ _numOtherAvatarsInView ] = otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND );
|
||||
// test other avatar hand position for proximity
|
||||
glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position );
|
||||
v -= _otherAvatarHandPosition[ _numOtherAvatarsInView ];
|
||||
v -= otherAvatar->getBonePosition( AVATAR_BONE_RIGHT_HAND );
|
||||
|
||||
float distance = glm::length( v );
|
||||
if ( distance < _maxArmLength ) {
|
||||
if ( distance < closestDistance ) {
|
||||
|
||||
//if ( distance < closestDistance ) { // perhaps I don't need this if we want to allow multi-avatar interactions
|
||||
{
|
||||
closestDistance = distance;
|
||||
_closestOtherAvatar = _numOtherAvatarsInView;
|
||||
_numOtherAvatarsInView++;
|
||||
_interactingOther = otherAvatar;
|
||||
_interactingOtherIsNearby = true;
|
||||
|
||||
// if I am holding hands with another avatar, a force is applied
|
||||
if (( _handState == 1 ) || ( _interactingOther->_handState == 1 )) {
|
||||
glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHolding.position;
|
||||
glm::vec3 vectorToMyHand = _bone[ AVATAR_BONE_RIGHT_HAND ].position - _handHolding.position;
|
||||
|
||||
_handHolding.velocity *= 0.7;
|
||||
_handHolding.velocity += ( vectorToOtherHand + vectorToMyHand ) * _handHolding.force * deltaTime;
|
||||
_handHolding.position += _handHolding.velocity;
|
||||
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _handHolding.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
///for testing only (prior to having real avs working)
|
||||
for (int o=0; o<NUM_OTHER_AVATARS; o++) {
|
||||
//-------------------------------------
|
||||
// test other avs for proximity...
|
||||
//-------------------------------------
|
||||
glm::vec3 v( _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position );
|
||||
v -= _DEBUG_otherAvatarListPosition[o];
|
||||
|
||||
float distance = glm::length( v );
|
||||
|
||||
if ( distance < _maxArmLength ) {
|
||||
if ( distance < closestDistance ) {
|
||||
closestDistance = distance;
|
||||
_closestOtherAvatar = o;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Set the vector we send for hand position to other people to be our right hand
|
||||
setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position);
|
||||
|
||||
}//if ( _isMine )
|
||||
|
||||
|
||||
updateArmIKAndConstraints( deltaTime );
|
||||
|
||||
if (!_interactingOtherIsNearby) {
|
||||
_interactingOther = NULL;
|
||||
}
|
||||
|
||||
if ( usingBigSphereCollisionTest ) {
|
||||
//--------------------------------------------------------------
|
||||
|
||||
// test for avatar collision response (using a big sphere :)
|
||||
//--------------------------------------------------------------
|
||||
updateBigSphereCollisionTest(deltaTime);
|
||||
updateAvatarCollisionDetectionAndResponse
|
||||
(
|
||||
_TEST_bigSpherePosition,
|
||||
_TEST_bigSphereRadius,
|
||||
_TEST_bigSphereRadius,
|
||||
glm::vec3( 0.0, 1.0, 0.0 ),
|
||||
deltaTime
|
||||
);
|
||||
}
|
||||
|
||||
if ( AVATAR_GRAVITY ) {
|
||||
if ( _bodyPosition.y > _bone[ AVATAR_BONE_RIGHT_FOOT ].radius * 2.0 ) {
|
||||
if ( _position.y > _bone[ AVATAR_BONE_RIGHT_FOOT ].radius * 2.0 ) {
|
||||
_velocity += glm::dvec3( 0.0, -1.0, 0.0 ) * ( 6.0 * deltaTime );
|
||||
}
|
||||
else {
|
||||
if ( _bodyPosition.y < _bone[ AVATAR_BONE_RIGHT_FOOT ].radius ) {
|
||||
_bodyPosition.y = _bone[ AVATAR_BONE_RIGHT_FOOT ].radius;
|
||||
if ( _position.y < _bone[ AVATAR_BONE_RIGHT_FOOT ].radius ) {
|
||||
_position.y = _bone[ AVATAR_BONE_RIGHT_FOOT ].radius;
|
||||
_velocity.y = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------
|
||||
// update avatar skeleton
|
||||
//------------------------
|
||||
updateSkeleton();
|
||||
|
||||
//------------------------------------------------------------
|
||||
// reset hand and arm positions according to hand movement
|
||||
//------------------------------------------------------------
|
||||
if (_usingBodySprings) {
|
||||
updateHandMovement();
|
||||
// update body springs
|
||||
updateBodySprings( deltaTime );
|
||||
}
|
||||
|
||||
if ( _isMine ) { // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely)
|
||||
//-------------------------------------------------
|
||||
// this handles the avatar being driven around...
|
||||
//-------------------------------------------------
|
||||
// driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely)
|
||||
if ( _isMine ) {
|
||||
|
||||
_thrust = glm::vec3( 0.0, 0.0, 0.0 );
|
||||
|
||||
if (_driveKeys[FWD]) {
|
||||
|
@ -435,8 +428,6 @@ void Head::simulate(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------
|
||||
float translationalSpeed = glm::length( _velocity );
|
||||
float rotationalSpeed = fabs( _bodyYawDelta );
|
||||
if ( translationalSpeed + rotationalSpeed > 0.2 )
|
||||
|
@ -448,43 +439,27 @@ void Head::simulate(float deltaTime) {
|
|||
_mode = AVATAR_MODE_INTERACTING;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
// update body yaw by body yaw delta
|
||||
//----------------------------------------------------------
|
||||
if (_isMine) {
|
||||
_bodyYaw += _bodyYawDelta * deltaTime;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------
|
||||
// decay body yaw delta
|
||||
//----------------------------------------------------------
|
||||
_bodyYawDelta *= (1.0 - TEST_YAW_DECAY * deltaTime);
|
||||
|
||||
//----------------------------------------------------------
|
||||
// add thrust to velocity
|
||||
//----------------------------------------------------------
|
||||
_velocity += glm::dvec3(_thrust * deltaTime);
|
||||
|
||||
//----------------------------------------------------------
|
||||
// update position by velocity
|
||||
//----------------------------------------------------------
|
||||
_bodyPosition += (glm::vec3)_velocity * deltaTime;
|
||||
_position += (glm::vec3)_velocity * deltaTime;
|
||||
|
||||
//----------------------------------------------------------
|
||||
// decay velocity
|
||||
//----------------------------------------------------------
|
||||
_velocity *= ( 1.0 - LIN_VEL_DECAY * deltaTime );
|
||||
|
||||
//
|
||||
// Update Head information
|
||||
//
|
||||
|
||||
// we will be eventually getting head rotation from elsewhere. For now, just setting it to body rotation
|
||||
//_head.yaw = _bodyYaw;
|
||||
//_head.pitch = _bodyPitch;
|
||||
//_head.roll = _bodyRoll;
|
||||
|
||||
if (!_head.noise) {
|
||||
// Decay back toward center
|
||||
_headPitch *= (1.0f - DECAY * 2 * deltaTime);
|
||||
|
@ -572,28 +547,43 @@ void Head::simulate(float deltaTime) {
|
|||
_head.eyebrowRoll [1] *=-1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update audio trailing average for rendering facial animations
|
||||
const float AUDIO_AVERAGING_SECS = 0.05;
|
||||
_head.averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _head.averageLoudness +
|
||||
(deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness;
|
||||
}
|
||||
|
||||
|
||||
float Avatar::getGirth() {
|
||||
return COLLISION_BODY_RADIUS;
|
||||
}
|
||||
|
||||
float Avatar::getHeight() {
|
||||
return COLLISION_HEIGHT;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
glm::vec3 Avatar::getBodyUpDirection() {
|
||||
return _orientation.getUp();
|
||||
}
|
||||
|
||||
// This is a workspace for testing avatar body collision detection and response
|
||||
//--------------------------------------------------------------------------------
|
||||
void Head::updateBigSphereCollisionTest( float deltaTime ) {
|
||||
void Avatar::updateAvatarCollisionDetectionAndResponse
|
||||
( glm::vec3 collisionPosition, float collisionGirth, float collisionHeight, glm::vec3 collisionUpVector, float deltaTime ) {
|
||||
|
||||
float myBodyApproximateBoundingRadius = 1.0f;
|
||||
glm::vec3 vectorFromMyBodyToBigSphere(_bodyPosition - _TEST_bigSpherePosition);
|
||||
glm::vec3 vectorFromMyBodyToBigSphere(_position - collisionPosition);
|
||||
bool jointCollision = false;
|
||||
|
||||
float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere);
|
||||
if ( distanceToBigSphere < myBodyApproximateBoundingRadius + _TEST_bigSphereRadius)
|
||||
if ( distanceToBigSphere < myBodyApproximateBoundingRadius + collisionGirth )
|
||||
{
|
||||
for (int b=0; b<NUM_AVATAR_BONES; b++)
|
||||
{
|
||||
glm::vec3 vectorFromJointToBigSphereCenter(_bone[b].springyPosition - _TEST_bigSpherePosition);
|
||||
glm::vec3 vectorFromJointToBigSphereCenter(_bone[b].springyPosition - collisionPosition);
|
||||
float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter);
|
||||
float combinedRadius = _bone[b].radius + _TEST_bigSphereRadius;
|
||||
float combinedRadius = _bone[b].radius + collisionGirth;
|
||||
if ( distanceToBigSphereCenter < combinedRadius )
|
||||
{
|
||||
jointCollision = true;
|
||||
|
@ -606,7 +596,7 @@ void Head::updateBigSphereCollisionTest( float deltaTime ) {
|
|||
|
||||
_bone[b].springyVelocity += collisionForce * 30.0f * deltaTime;
|
||||
_velocity += collisionForce * 100.0f * deltaTime;
|
||||
_bone[b].springyPosition = _TEST_bigSpherePosition + directionVector * combinedRadius;
|
||||
_bone[b].springyPosition = collisionPosition + directionVector * combinedRadius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -620,26 +610,19 @@ void Head::updateBigSphereCollisionTest( float deltaTime ) {
|
|||
}
|
||||
}
|
||||
|
||||
void Avatar::render(bool lookingInMirror) {
|
||||
|
||||
|
||||
|
||||
void Head::render(bool lookingInMirror) {
|
||||
|
||||
//---------------------------------------------------
|
||||
// show avatar position
|
||||
//---------------------------------------------------
|
||||
glColor4f( 0.5f, 0.5f, 0.5f, 0.6 );
|
||||
glPushMatrix();
|
||||
glTranslatef(_bodyPosition.x, _bodyPosition.y, _bodyPosition.z);
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
glScalef( 0.03, 0.03, 0.03 );
|
||||
glutSolidSphere( 1, 10, 10 );
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
if ( usingBigSphereCollisionTest ) {
|
||||
//---------------------------------------------------
|
||||
|
||||
// show TEST big sphere
|
||||
//---------------------------------------------------
|
||||
glColor4f( 0.5f, 0.6f, 0.8f, 0.7 );
|
||||
glPushMatrix();
|
||||
glTranslatef(_TEST_bigSpherePosition.x, _TEST_bigSpherePosition.y, _TEST_bigSpherePosition.z);
|
||||
|
@ -648,39 +631,19 @@ void Head::render(bool lookingInMirror) {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
// render body
|
||||
//---------------------------------------------------
|
||||
renderBody();
|
||||
|
||||
//---------------------------------------------------
|
||||
// render head
|
||||
//---------------------------------------------------
|
||||
renderHead(lookingInMirror);
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// if this is my avatar, then render my interactions with the other avatars
|
||||
//---------------------------------------------------------------------------
|
||||
// if this is my avatar, then render my interactions with the other avatar
|
||||
if ( _isMine )
|
||||
{
|
||||
/*
|
||||
//---------------------------------------------------
|
||||
// render other avatars (DEBUG TEST)
|
||||
//---------------------------------------------------
|
||||
for (int o=0; o<_numOtherAvatarsInView; o++) {
|
||||
glPushMatrix();
|
||||
glTranslatef( _otherAvatarHandPosition[o].x, _otherAvatarHandPosition[o].y, _otherAvatarHandPosition[o].z );
|
||||
glScalef( 0.03, 0.03, 0.03 );
|
||||
glutSolidSphere( 1, 10, 10 );
|
||||
glPopMatrix();
|
||||
}
|
||||
*/
|
||||
|
||||
if (_usingBodySprings) {
|
||||
if ( _closestOtherAvatar != -1 ) {
|
||||
if ( _interactingOtherIsNearby ) {
|
||||
|
||||
glm::vec3 v1( _bone[ AVATAR_BONE_RIGHT_HAND ].position );
|
||||
glm::vec3 v2( _otherAvatarHandPosition[ _closestOtherAvatar ] );
|
||||
glm::vec3 v2( _interactingOther->_handPosition );
|
||||
|
||||
glLineWidth( 8.0 );
|
||||
glColor4f( 0.7f, 0.4f, 0.1f, 0.6 );
|
||||
|
@ -690,20 +653,16 @@ void Head::render(bool lookingInMirror) {
|
|||
glEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Head::renderHead(bool lookingInMirror) {
|
||||
void Avatar::renderHead(bool lookingInMirror) {
|
||||
int side = 0;
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_RESCALE_NORMAL);
|
||||
|
||||
//---------------------------------------------------
|
||||
// show head orientation
|
||||
//---------------------------------------------------
|
||||
//renderOrientationDirections( _bone[ AVATAR_BONE_HEAD ].position, _bone[ AVATAR_BONE_HEAD ].orientation, 0.2f );
|
||||
|
||||
glPushMatrix();
|
||||
|
@ -748,16 +707,20 @@ void Head::renderHead(bool lookingInMirror) {
|
|||
}
|
||||
glPopMatrix();
|
||||
|
||||
// _eyebrows
|
||||
|
||||
// Update audio attack data for facial animation (eyebrows and mouth)
|
||||
_head.audioAttack = 0.9 * _head.audioAttack + 0.1 * fabs(_audioLoudness - _head.lastLoudness);
|
||||
_head.lastLoudness = _audioLoudness;
|
||||
|
||||
|
||||
const float BROW_LIFT_THRESHOLD = 100;
|
||||
if (_head.audioAttack > BROW_LIFT_THRESHOLD)
|
||||
_head.browAudioLift += sqrt(_head.audioAttack) / 1000.0;
|
||||
|
||||
_head.browAudioLift *= .90;
|
||||
|
||||
|
||||
// Render Eyebrows
|
||||
glPushMatrix();
|
||||
glTranslatef(-_head.interBrowDistance / 2.0,0.4,0.45);
|
||||
for(side = 0; side < 2; side++) {
|
||||
|
@ -855,7 +818,7 @@ void Head::renderHead(bool lookingInMirror) {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
void Head::startHandMovement() {
|
||||
void Avatar::startHandMovement() {
|
||||
|
||||
if (!_usingBodySprings) {
|
||||
initializeBodySprings();
|
||||
|
@ -863,19 +826,19 @@ void Head::startHandMovement() {
|
|||
}
|
||||
}
|
||||
|
||||
void Head::stopHandMovement() {
|
||||
void Avatar::stopHandMovement() {
|
||||
//_usingBodySprings = false;
|
||||
}
|
||||
|
||||
void Head::setHandMovementValues( glm::vec3 handOffset ) {
|
||||
void Avatar::setHandMovementValues( glm::vec3 handOffset ) {
|
||||
_movedHandOffset = handOffset;
|
||||
}
|
||||
|
||||
AvatarMode Head::getMode() {
|
||||
AvatarMode Avatar::getMode() {
|
||||
return _mode;
|
||||
}
|
||||
|
||||
void Head::initializeSkeleton() {
|
||||
void Avatar::initializeSkeleton() {
|
||||
|
||||
for (int b=0; b<NUM_AVATAR_BONES; b++) {
|
||||
_bone[b].parent = AVATAR_BONE_NULL;
|
||||
|
@ -920,9 +883,7 @@ void Head::initializeSkeleton() {
|
|||
_bone[ AVATAR_BONE_RIGHT_SHIN ].parent = AVATAR_BONE_RIGHT_THIGH;
|
||||
_bone[ AVATAR_BONE_RIGHT_FOOT ].parent = AVATAR_BONE_RIGHT_SHIN;
|
||||
|
||||
//----------------------------------------------------------
|
||||
// specify the default pose position
|
||||
//----------------------------------------------------------
|
||||
_bone[ AVATAR_BONE_PELVIS_SPINE ].defaultPosePosition = glm::vec3( 0.0, 0.3, 0.0 );
|
||||
_bone[ AVATAR_BONE_MID_SPINE ].defaultPosePosition = glm::vec3( 0.0, 0.1, 0.0 );
|
||||
_bone[ AVATAR_BONE_CHEST_SPINE ].defaultPosePosition = glm::vec3( 0.0, 0.06, 0.0 );
|
||||
|
@ -972,21 +933,14 @@ void Head::initializeSkeleton() {
|
|||
_bone[ AVATAR_BONE_RIGHT_SHIN ].radius = 0.015;
|
||||
_bone[ AVATAR_BONE_RIGHT_FOOT ].radius = 0.02;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// calculate bone length
|
||||
//----------------------------------------------------------------------------
|
||||
calculateBoneLengths();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// generate world positions
|
||||
//----------------------------------------------------------------------------
|
||||
updateSkeleton();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Head::calculateBoneLengths() {
|
||||
void Avatar::calculateBoneLengths() {
|
||||
for (int b=0; b<NUM_AVATAR_BONES; b++) {
|
||||
_bone[b].length = glm::length( _bone[b].defaultPosePosition );
|
||||
}
|
||||
|
@ -997,31 +951,28 @@ void Head::calculateBoneLengths() {
|
|||
+ _bone[ AVATAR_BONE_RIGHT_HAND ].length;
|
||||
}
|
||||
|
||||
void Head::updateSkeleton() {
|
||||
//----------------------------------
|
||||
void Avatar::updateSkeleton() {
|
||||
// rotate body...
|
||||
//----------------------------------
|
||||
_orientation.setToIdentity();
|
||||
_orientation.yaw( _bodyYaw );
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// calculate positions of all bones by traversing the skeleton tree:
|
||||
//------------------------------------------------------------------------
|
||||
for (int b=0; b<NUM_AVATAR_BONES; b++) {
|
||||
if ( _bone[b].parent == AVATAR_BONE_NULL ) {
|
||||
_bone[b].orientation.set( _orientation );
|
||||
_bone[b].position = _bodyPosition;
|
||||
_bone[b].position = _position;
|
||||
}
|
||||
else {
|
||||
_bone[b].orientation.set( _bone[ _bone[b].parent ].orientation );
|
||||
_bone[b].position = _bone[ _bone[b].parent ].position;
|
||||
}
|
||||
|
||||
///TEST! - get this working and then add a comment; JJV
|
||||
// if this is not my avatar, then hand position comes from transmitted data
|
||||
if ( ! _isMine ) {
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _handPosition;
|
||||
}
|
||||
|
||||
// the following will be replaced by a proper rotation...
|
||||
float xx = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getRight() );
|
||||
float yy = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getUp () );
|
||||
float zz = glm::dot( _bone[b].defaultPosePosition, _bone[b].orientation.getFront() );
|
||||
|
@ -1035,8 +986,7 @@ void Head::updateSkeleton() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void Head::initializeBodySprings() {
|
||||
void Avatar::initializeBodySprings() {
|
||||
for (int b=0; b<NUM_AVATAR_BONES; b++) {
|
||||
_bone[b].springyPosition = _bone[b].position;
|
||||
_bone[b].springyVelocity = glm::vec3( 0.0f, 0.0f, 0.0f );
|
||||
|
@ -1044,12 +994,12 @@ void Head::initializeBodySprings() {
|
|||
}
|
||||
|
||||
|
||||
void Head::updateBodySprings( float deltaTime ) {
|
||||
void Avatar::updateBodySprings( float deltaTime ) {
|
||||
for (int b=0; b<NUM_AVATAR_BONES; b++) {
|
||||
glm::vec3 springVector( _bone[b].springyPosition );
|
||||
|
||||
if ( _bone[b].parent == AVATAR_BONE_NULL ) {
|
||||
springVector -= _bodyPosition;
|
||||
springVector -= _position;
|
||||
}
|
||||
else {
|
||||
springVector -= _bone[ _bone[b].parent ].springyPosition;
|
||||
|
@ -1084,7 +1034,7 @@ void Head::updateBodySprings( float deltaTime ) {
|
|||
}
|
||||
}
|
||||
|
||||
glm::vec3 Head::getHeadLookatDirection() {
|
||||
glm::vec3 Avatar::getHeadLookatDirection() {
|
||||
return glm::vec3
|
||||
(
|
||||
_orientation.getFront().x,
|
||||
|
@ -1093,7 +1043,7 @@ glm::vec3 Head::getHeadLookatDirection() {
|
|||
);
|
||||
}
|
||||
|
||||
glm::vec3 Head::getHeadLookatDirectionUp() {
|
||||
glm::vec3 Avatar::getHeadLookatDirectionUp() {
|
||||
return glm::vec3
|
||||
(
|
||||
_orientation.getUp().x,
|
||||
|
@ -1102,7 +1052,7 @@ glm::vec3 Head::getHeadLookatDirectionUp() {
|
|||
);
|
||||
}
|
||||
|
||||
glm::vec3 Head::getHeadLookatDirectionRight() {
|
||||
glm::vec3 Avatar::getHeadLookatDirectionRight() {
|
||||
return glm::vec3
|
||||
(
|
||||
_orientation.getRight().x,
|
||||
|
@ -1111,7 +1061,7 @@ glm::vec3 Head::getHeadLookatDirectionRight() {
|
|||
);
|
||||
}
|
||||
|
||||
glm::vec3 Head::getHeadPosition() {
|
||||
glm::vec3 Avatar::getHeadPosition() {
|
||||
|
||||
if ( _usingBodySprings ) {
|
||||
return _bone[ AVATAR_BONE_HEAD ].springyPosition;
|
||||
|
@ -1121,13 +1071,13 @@ glm::vec3 Head::getHeadPosition() {
|
|||
}
|
||||
|
||||
|
||||
glm::vec3 Head::getBonePosition( AvatarBoneID b ) {
|
||||
glm::vec3 Avatar::getBonePosition( AvatarBoneID b ) {
|
||||
return _bone[b].position;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Head::updateHandMovement() {
|
||||
void Avatar::updateHandMovement( float deltaTime ) {
|
||||
glm::vec3 transformedHandMovement;
|
||||
|
||||
transformedHandMovement
|
||||
|
@ -1137,41 +1087,24 @@ void Head::updateHandMovement() {
|
|||
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].position += transformedHandMovement;
|
||||
|
||||
setHandState(_mousePressed);
|
||||
|
||||
//if holding hands, add a pull to the hand...
|
||||
if ( _usingBodySprings ) {
|
||||
if ( _closestOtherAvatar != -1 ) {
|
||||
if ( _mousePressed ) {
|
||||
|
||||
glm::vec3 handToHandVector( _otherAvatarHandPosition[ _closestOtherAvatar ]);
|
||||
handToHandVector -= _bone[ AVATAR_BONE_RIGHT_HAND ].position;
|
||||
|
||||
//_bone[ AVATAR_BONE_RIGHT_HAND ].springyVelocity -= handPull;
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _otherAvatarHandPosition[ _closestOtherAvatar ];
|
||||
}
|
||||
}
|
||||
if (_isMine) {
|
||||
_handState = _mousePressed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Avatar::updateArmIKAndConstraints( float deltaTime ) {
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// determine the arm vector
|
||||
//-------------------------------------------------------------------------------
|
||||
glm::vec3 armVector = _bone[ AVATAR_BONE_RIGHT_HAND ].position;
|
||||
armVector -= _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// test to see if right hand is being dragged beyond maximum arm length
|
||||
//-------------------------------------------------------------------------------
|
||||
float distance = glm::length( armVector );
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// if right hand is being dragged beyond maximum arm length...
|
||||
//-------------------------------------------------------------------------------
|
||||
if ( distance > _maxArmLength ) {
|
||||
//-------------------------------------------------------------------------------
|
||||
// reset right hand to be constrained to maximum arm length
|
||||
//-------------------------------------------------------------------------------
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].position = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position;
|
||||
glm::vec3 armNormal = armVector / distance;
|
||||
armVector = armNormal * _maxArmLength;
|
||||
|
@ -1181,57 +1114,32 @@ void Head::updateHandMovement() {
|
|||
_bone[ AVATAR_BONE_RIGHT_HAND ].position = constrainedPosition;
|
||||
}
|
||||
|
||||
/*
|
||||
//-------------------------------------------------------------------------------
|
||||
// keep arm from going through av body...
|
||||
//-------------------------------------------------------------------------------
|
||||
glm::vec3 adjustedArmVector = _bone[ AVATAR_BONE_RIGHT_HAND ].position;
|
||||
adjustedArmVector -= _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position;
|
||||
|
||||
float rightComponent = glm::dot( adjustedArmVector, avatar.orientation.getRight() );
|
||||
|
||||
if ( rightComponent < 0.0 )
|
||||
{
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].position -= avatar.orientation.getRight() * rightComponent;
|
||||
}
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// set elbow position
|
||||
//-----------------------------------------------------------------------------
|
||||
glm::vec3 newElbowPosition = _bone[ AVATAR_BONE_RIGHT_SHOULDER ].position;
|
||||
newElbowPosition += armVector * ONE_HALF;
|
||||
//glm::vec3 perpendicular = glm::cross( frontDirection, armVector );
|
||||
glm::vec3 perpendicular = glm::cross( _orientation.getFront(), armVector );
|
||||
|
||||
newElbowPosition += perpendicular * ( 1.0f - ( _maxArmLength / distance ) ) * ONE_HALF;
|
||||
_bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position = newElbowPosition;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// set wrist position
|
||||
//-----------------------------------------------------------------------------
|
||||
glm::vec3 vv( _bone[ AVATAR_BONE_RIGHT_HAND ].position );
|
||||
vv -= _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position;
|
||||
glm::vec3 newWristPosition = _bone[ AVATAR_BONE_RIGHT_UPPER_ARM ].position;
|
||||
newWristPosition += vv * 0.7f;
|
||||
_bone[ AVATAR_BONE_RIGHT_FOREARM ].position = newWristPosition;
|
||||
|
||||
// Set the vector we send for hand position to other people to be our right hand
|
||||
setHandPosition(_bone[ AVATAR_BONE_RIGHT_HAND ].position);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Head::renderBody() {
|
||||
//-----------------------------------------
|
||||
|
||||
void Avatar::renderBody() {
|
||||
|
||||
// Render bone positions as spheres
|
||||
//-----------------------------------------
|
||||
for (int b=0; b<NUM_AVATAR_BONES; b++) {
|
||||
//renderBoneAsBlock( (AvatarBoneID)b);
|
||||
|
||||
//render bone orientation
|
||||
renderOrientationDirections( _bone[b].springyPosition, _bone[b].orientation, _bone[b].radius * 2.0 );
|
||||
//renderOrientationDirections( _bone[b].springyPosition, _bone[b].orientation, _bone[b].radius * 2.0 );
|
||||
|
||||
if ( _usingBodySprings ) {
|
||||
glColor3fv( skinColor );
|
||||
|
@ -1249,9 +1157,7 @@ void Head::renderBody() {
|
|||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Render lines connecting the bone positions
|
||||
//-----------------------------------------------------
|
||||
if ( _usingBodySprings ) {
|
||||
glColor3f( 0.4f, 0.5f, 0.6f );
|
||||
glLineWidth(3.0);
|
||||
|
@ -1279,8 +1185,8 @@ void Head::renderBody() {
|
|||
}
|
||||
}
|
||||
|
||||
if (( _usingBodySprings ) && ( getHandState() )) {
|
||||
glColor4f( 1.0, 1.0, 0.5, 0.5 );
|
||||
// if the hand is grasping, show it...
|
||||
if (( _usingBodySprings ) && ( _handState == 1 )) {
|
||||
glPushMatrix();
|
||||
glTranslatef
|
||||
(
|
||||
|
@ -1288,14 +1194,15 @@ void Head::renderBody() {
|
|||
_bone[ AVATAR_BONE_RIGHT_HAND ].springyPosition.y,
|
||||
_bone[ AVATAR_BONE_RIGHT_HAND ].springyPosition.z
|
||||
);
|
||||
glutSolidSphere( 0.03f, 10.0f, 5.0f );
|
||||
glColor4f( 1.0, 1.0, 0.8, 0.3 ); glutSolidSphere( 0.020f, 10.0f, 10.0f );
|
||||
glColor4f( 1.0, 1.0, 0.4, 0.2 ); glutSolidSphere( 0.025f, 10.0f, 10.0f );
|
||||
glColor4f( 1.0, 1.0, 0.2, 0.1 ); glutSolidSphere( 0.030f, 10.0f, 10.0f );
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Head::renderBoneAsBlock( AvatarBoneID b ) {
|
||||
void Avatar::renderBoneAsBlock( AvatarBoneID b ) {
|
||||
glColor3fv( skinColor );
|
||||
glPushMatrix();
|
||||
glTranslatef( _bone[b].springyPosition.x, _bone[b].springyPosition.y, _bone[b].springyPosition.z );
|
||||
|
@ -1307,13 +1214,13 @@ void Head::renderBoneAsBlock( AvatarBoneID b ) {
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
void Head::SetNewHeadTarget(float pitch, float yaw) {
|
||||
void Avatar::SetNewHeadTarget(float pitch, float yaw) {
|
||||
_head.pitchTarget = pitch;
|
||||
_head.yawTarget = yaw;
|
||||
}
|
||||
|
||||
// getting data from Android transmitte app
|
||||
void Head::processTransmitterData(unsigned char* packetData, int numBytes) {
|
||||
void Avatar::processTransmitterData(unsigned char* packetData, int numBytes) {
|
||||
// Read a packet from a transmitter app, process the data
|
||||
float accX, accY, accZ,
|
||||
graX, graY, graZ,
|
|
@ -1,13 +1,13 @@
|
|||
//
|
||||
// Head.h
|
||||
// Avatar.h
|
||||
// interface
|
||||
//
|
||||
// Created by Philip Rosedale on 9/11/12.
|
||||
// Copyright (c) 2012 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef __interface__head__
|
||||
#define __interface__head__
|
||||
#ifndef __interface__avatar__
|
||||
#define __interface__avatar__
|
||||
|
||||
#include <AvatarData.h>
|
||||
#include <Orientation.h>
|
||||
|
@ -29,6 +29,9 @@ const float YAW_MAG = 300.0;
|
|||
const float TEST_YAW_DECAY = 5.0;
|
||||
const float LIN_VEL_DECAY = 5.0;
|
||||
|
||||
const float COLLISION_BODY_RADIUS = 0.1;
|
||||
const float COLLISION_HEIGHT = 1.5;
|
||||
|
||||
enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH};
|
||||
|
||||
#define FWD 0
|
||||
|
@ -41,7 +44,7 @@ enum eyeContactTargets {LEFT_EYE, RIGHT_EYE, MOUTH};
|
|||
#define ROT_RIGHT 7
|
||||
#define MAX_DRIVE_KEYS 8
|
||||
|
||||
#define MAX_OTHER_AVATARS 50 // temporary - for testing purposes!
|
||||
#define MAX_OTHER_AVATARS 10 // temporary - for testing purposes!
|
||||
|
||||
enum AvatarMode
|
||||
{
|
||||
|
@ -81,6 +84,22 @@ enum AvatarBoneID
|
|||
NUM_AVATAR_BONES
|
||||
};
|
||||
|
||||
struct AvatarCollisionElipsoid
|
||||
{
|
||||
bool colliding;
|
||||
glm::vec3 position;
|
||||
float girth;
|
||||
float height;
|
||||
glm::vec3 upVector;
|
||||
};
|
||||
|
||||
struct AvatarHandHolding
|
||||
{
|
||||
glm::vec3 position;
|
||||
glm::vec3 velocity;
|
||||
float force;
|
||||
};
|
||||
|
||||
struct AvatarBone
|
||||
{
|
||||
AvatarBoneID parent; // which bone is this bone connected to?
|
||||
|
@ -137,12 +156,12 @@ struct AvatarHead
|
|||
};
|
||||
|
||||
|
||||
class Head : public AvatarData {
|
||||
class Avatar : public AvatarData {
|
||||
public:
|
||||
Head(bool isMine);
|
||||
~Head();
|
||||
Head(const Head &otherHead);
|
||||
Head* clone() const;
|
||||
Avatar(bool isMine);
|
||||
~Avatar();
|
||||
Avatar(const Avatar &otherAvatar);
|
||||
Avatar* clone() const;
|
||||
|
||||
void reset();
|
||||
void UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity);
|
||||
|
@ -164,6 +183,9 @@ class Head : public AvatarData {
|
|||
glm::vec3 getHeadLookatDirectionRight();
|
||||
glm::vec3 getHeadPosition();
|
||||
glm::vec3 getBonePosition( AvatarBoneID b );
|
||||
glm::vec3 getBodyUpDirection();
|
||||
float getGirth();
|
||||
float getHeight();
|
||||
|
||||
AvatarMode getMode();
|
||||
|
||||
|
@ -175,7 +197,8 @@ class Head : public AvatarData {
|
|||
void startHandMovement();
|
||||
void stopHandMovement();
|
||||
void setHandMovementValues( glm::vec3 movement );
|
||||
void updateHandMovement();
|
||||
void updateHandMovement( float deltaTime );
|
||||
void updateArmIKAndConstraints( float deltaTime );
|
||||
|
||||
float getAverageLoudness() {return _head.averageLoudness;};
|
||||
void setAverageLoudness(float al) {_head.averageLoudness = al;};
|
||||
|
@ -191,10 +214,7 @@ class Head : public AvatarData {
|
|||
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
||||
glm::vec3 getThrust() { return _thrust; };
|
||||
|
||||
//
|
||||
// Related to getting transmitter UDP data used to animate the avatar hand
|
||||
//
|
||||
|
||||
void processTransmitterData(unsigned char * packetData, int numBytes);
|
||||
float getTransmitterHz() { return _transmitterHz; };
|
||||
|
||||
|
@ -203,10 +223,8 @@ class Head : public AvatarData {
|
|||
bool _isMine;
|
||||
glm::vec3 _TEST_bigSpherePosition;
|
||||
float _TEST_bigSphereRadius;
|
||||
glm::vec3 _otherAvatarHandPosition[ MAX_OTHER_AVATARS ];
|
||||
bool _mousePressed;
|
||||
float _bodyYawDelta;
|
||||
int _closestOtherAvatar;
|
||||
bool _usingBodySprings;
|
||||
glm::vec3 _movedHandOffset;
|
||||
float _springVelocityDecay;
|
||||
|
@ -214,35 +232,37 @@ class Head : public AvatarData {
|
|||
glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion
|
||||
AvatarBone _bone[ NUM_AVATAR_BONES ];
|
||||
AvatarMode _mode;
|
||||
AvatarHandHolding _handHolding;
|
||||
glm::dvec3 _velocity;
|
||||
glm::vec3 _thrust;
|
||||
float _maxArmLength;
|
||||
Orientation _orientation;
|
||||
int _numOtherAvatarsInView;
|
||||
int _driveKeys[MAX_DRIVE_KEYS];
|
||||
GLUquadric* _sphere;
|
||||
float _renderYaw;
|
||||
float _renderPitch; // Pitch from view frustum when this is own head.
|
||||
|
||||
//
|
||||
// Related to getting transmitter UDP data used to animate the avatar hand
|
||||
//
|
||||
float _renderPitch; // Pitch from view frustum when this is own head
|
||||
timeval _transmitterTimer;
|
||||
float _transmitterHz;
|
||||
int _transmitterPackets;
|
||||
Avatar* _interactingOther;
|
||||
bool _interactingOtherIsNearby;
|
||||
|
||||
//-----------------------------
|
||||
// private methods...
|
||||
//-----------------------------
|
||||
void initializeSkeleton();
|
||||
void updateSkeleton();
|
||||
void initializeBodySprings();
|
||||
void updateBodySprings( float deltaTime );
|
||||
void calculateBoneLengths();
|
||||
void updateBigSphereCollisionTest( float deltaTime );
|
||||
void readSensors();
|
||||
void renderBoneAsBlock( AvatarBoneID b );
|
||||
|
||||
void updateAvatarCollisionDetectionAndResponse
|
||||
(
|
||||
glm::vec3 collisionPosition,
|
||||
float collisionGirth,
|
||||
float collisionHeight,
|
||||
glm::vec3 collisionUpVector,
|
||||
float deltaTime
|
||||
);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -46,6 +46,7 @@ Cloud::Cloud(int num,
|
|||
void Cloud::render() {
|
||||
|
||||
float particleAttenuationQuadratic[] = { 0.0f, 0.0f, 2.0f };
|
||||
float particleAttenuationConstant[] = { 1.0f, 0.0f, 0.0f };
|
||||
|
||||
glEnable( GL_TEXTURE_2D );
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
|
@ -73,6 +74,10 @@ void Cloud::render() {
|
|||
glEnd();
|
||||
glDisable( GL_POINT_SPRITE_ARB );
|
||||
glDisable( GL_TEXTURE_2D );
|
||||
|
||||
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particleAttenuationConstant );
|
||||
glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, 1.0f );
|
||||
glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 0.0f );
|
||||
}
|
||||
|
||||
void Cloud::simulate (float deltaTime) {
|
||||
|
|
|
@ -55,7 +55,7 @@ class Log {
|
|||
public:
|
||||
|
||||
explicit Log(FILE* tPipeTo = stdout, unsigned bufferedLines = 1024,
|
||||
unsigned defaultLogWidth = 240, unsigned defaultCharWidth = 6, unsigned defaultCharHeight = 20);
|
||||
unsigned defaultLogWidth = 400, unsigned defaultCharWidth = 6, unsigned defaultCharHeight = 20);
|
||||
~Log();
|
||||
|
||||
void setLogWidth(unsigned pixels);
|
||||
|
|
|
@ -34,7 +34,17 @@ float Stars::changeLOD(float fraction, float overalloc, float realloc) {
|
|||
return float(_ptrController->changeLOD(fraction, overalloc, realloc));
|
||||
}
|
||||
|
||||
void Stars::render(float fovDiagonal, float aspect, glm::mat4 const& view) {
|
||||
void Stars::render(float fovY, float aspect, float nearZ) {
|
||||
|
||||
// determine length of screen diagonal from quadrant height and aspect ratio
|
||||
float quadrantHeight = nearZ * tan(angleConvert<Degrees,Radians>(fovY) * 0.5f);
|
||||
float halfDiagonal = sqrt(quadrantHeight * quadrantHeight * (1.0f + aspect * aspect));
|
||||
|
||||
// determine fov angle in respect to the diagonal
|
||||
float fovDiagonal = atan(halfDiagonal / nearZ) * 2.0f;
|
||||
|
||||
// pull the modelview matrix off the GL stack
|
||||
glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
|
||||
|
||||
_ptrController->render(fovDiagonal, aspect, glm::affineInverse(view));
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
|
||||
namespace starfield { class Controller; }
|
||||
|
||||
/**
|
||||
* Starfield rendering component.
|
||||
*/
|
||||
//
|
||||
// Starfield rendering component.
|
||||
//
|
||||
class Stars {
|
||||
|
||||
starfield::Controller* _ptrController;
|
||||
|
@ -25,47 +25,47 @@ class Stars {
|
|||
Stars();
|
||||
~Stars();
|
||||
|
||||
/**
|
||||
* Reads input file from URL. Returns true upon success.
|
||||
*
|
||||
* The limit parameter allows to reduce the number of stars
|
||||
* that are loaded, keeping the brightest ones.
|
||||
*/
|
||||
//
|
||||
// Reads input file from URL. Returns true upon success.
|
||||
//
|
||||
// The limit parameter allows to reduce the number of stars
|
||||
// that are loaded, keeping the brightest ones.
|
||||
//
|
||||
bool readInput(const char* url, const char* cacheFile = 0l, unsigned limit = 200000);
|
||||
|
||||
/**
|
||||
* Renders the starfield from a local viewer's perspective.
|
||||
* The parameter specifies the field of view.
|
||||
*/
|
||||
void render(float fovDiagonal, float aspect, glm::mat4 const& view);
|
||||
//
|
||||
// Renders the starfield from a local viewer's perspective.
|
||||
// The parameters specifiy the field of view.
|
||||
//
|
||||
void render(float fovY, float aspect, float nearZ);
|
||||
|
||||
/**
|
||||
* Sets the resolution for FOV culling.
|
||||
*
|
||||
* The parameter determines the number of tiles in azimuthal
|
||||
* and altitudinal directions.
|
||||
*
|
||||
* GPU resources are updated upon change in which case 'true'
|
||||
* is returned.
|
||||
*/
|
||||
//
|
||||
// Sets the resolution for FOV culling.
|
||||
//
|
||||
// The parameter determines the number of tiles in azimuthal
|
||||
// and altitudinal directions.
|
||||
//
|
||||
// GPU resources are updated upon change in which case 'true'
|
||||
// is returned.
|
||||
//
|
||||
bool setResolution(unsigned k);
|
||||
|
||||
/**
|
||||
* Allows to alter the number of stars to be rendered given a
|
||||
* factor. The least brightest ones are omitted first.
|
||||
*
|
||||
* The further parameters determine when GPU resources should
|
||||
* be reallocated. Its value is fractional in respect to the
|
||||
* last number of stars 'n' that caused 'n * (1+overalloc)' to
|
||||
* be allocated. When the next call to setLOD causes the total
|
||||
* number of stars that could be rendered to drop below 'n *
|
||||
* (1-realloc)' or rises above 'n * (1+realloc)' GPU resources
|
||||
* are updated. Note that all parameters must be fractions,
|
||||
* that is within the range [0;1] and that 'overalloc' must be
|
||||
* greater than or equal to 'realloc'.
|
||||
*
|
||||
* The current level of detail is returned as a float in [0;1].
|
||||
*/
|
||||
//
|
||||
// Allows to alter the number of stars to be rendered given a
|
||||
// factor. The least brightest ones are omitted first.
|
||||
//
|
||||
// The further parameters determine when GPU resources should
|
||||
// be reallocated. Its value is fractional in respect to the
|
||||
// last number of stars 'n' that caused 'n * (1+overalloc)' to
|
||||
// be allocated. When the next call to setLOD causes the total
|
||||
// number of stars that could be rendered to drop below 'n *
|
||||
// (1-realloc)' or rises above 'n * (1+realloc)' GPU resources
|
||||
// are updated. Note that all parameters must be fractions,
|
||||
// that is within the range [0;1] and that 'overalloc' must be
|
||||
// greater than or equal to 'realloc'.
|
||||
//
|
||||
// The current level of detail is returned as a float in [0;1].
|
||||
//
|
||||
float changeLOD(float factor,
|
||||
float overalloc = 0.25, float realloc = 0.15);
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ void render_vector(glm::vec3 * vec)
|
|||
// Draw marker dots for magnitude
|
||||
glEnd();
|
||||
float particleAttenuationQuadratic[] = { 0.0f, 0.0f, 2.0f }; // larger Z = smaller particles
|
||||
float particleAttenuationConstant[] = { 1.0f, 0.0f, 0.0f };
|
||||
|
||||
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particleAttenuationQuadratic );
|
||||
|
||||
|
@ -104,6 +105,7 @@ void render_vector(glm::vec3 * vec)
|
|||
glVertex3f(0,0,vec->z);
|
||||
glEnd();
|
||||
|
||||
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particleAttenuationConstant );
|
||||
}
|
||||
|
||||
void render_world_box()
|
||||
|
|
|
@ -23,25 +23,27 @@
|
|||
|
||||
const int MAX_VOXELS_PER_SYSTEM = 250000;
|
||||
|
||||
const int VERTICES_PER_VOXEL = 8;
|
||||
const int VERTICES_PER_VOXEL = 24;
|
||||
const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
||||
const int INDICES_PER_VOXEL = 3 * 12;
|
||||
|
||||
float identityVertices[] = { 0, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1,
|
||||
1, 0, 1,
|
||||
1, 1, 1,
|
||||
0, 1, 1 };
|
||||
float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1,
|
||||
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1,
|
||||
0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 };
|
||||
|
||||
GLubyte identityIndices[] = { 0,1,2, 0,2,3,
|
||||
0,1,5, 0,4,5,
|
||||
0,3,7, 0,4,7,
|
||||
1,2,6, 1,5,6,
|
||||
2,3,7, 2,6,7,
|
||||
4,5,6, 4,6,7 };
|
||||
GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1,
|
||||
0,0,+1, 0,0,+1, 0,0,+1, 0,0,+1,
|
||||
0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0,
|
||||
0,-1,0, 0,-1,0, 0,+1,0, 0,+1,0,
|
||||
-1,0,0, +1,0,0, +1,0,0, -1,0,0,
|
||||
-1,0,0, +1,0,0, +1,0,0, -1,0,0 };
|
||||
|
||||
GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- .
|
||||
8,9,13, 8,13,12, // Y-
|
||||
16,23,19, 16,20,23, // X-
|
||||
17,18,22, 17,22,21, // X+
|
||||
10,11,15, 10,15,14, // Y+
|
||||
4,5,6, 4,6,7 }; // Z+ .
|
||||
|
||||
VoxelSystem::VoxelSystem() {
|
||||
voxelsRendered = 0;
|
||||
|
@ -58,8 +60,8 @@ VoxelSystem::~VoxelSystem() {
|
|||
pthread_mutex_destroy(&bufferWriteLock);
|
||||
}
|
||||
|
||||
void VoxelSystem::setViewerHead(Head *newViewerHead) {
|
||||
viewerHead = newViewerHead;
|
||||
void VoxelSystem::setViewerAvatar(Avatar *newViewerAvatar) {
|
||||
viewerAvatar = newViewerAvatar;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -258,7 +260,7 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosi
|
|||
int voxelsAdded = 0;
|
||||
|
||||
float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE);
|
||||
glm::vec3 viewerPosition = viewerHead->getBodyPosition();
|
||||
glm::vec3 viewerPosition = viewerAvatar->getPosition();
|
||||
|
||||
// debug LOD code
|
||||
glm::vec3 debugNodePosition;
|
||||
|
@ -359,11 +361,28 @@ void VoxelSystem::init() {
|
|||
}
|
||||
}
|
||||
|
||||
GLfloat *normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
GLfloat *normalsArrayEndPointer = normalsArray;
|
||||
|
||||
// populate the normalsArray
|
||||
for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) {
|
||||
for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) {
|
||||
*(normalsArrayEndPointer++) = identityNormals[i];
|
||||
}
|
||||
}
|
||||
|
||||
// VBO for the verticesArray
|
||||
glGenBuffers(1, &vboVerticesID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
// VBO for the normalsArray
|
||||
glGenBuffers(1, &vboNormalsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM,
|
||||
normalsArray, GL_STATIC_DRAW);
|
||||
|
||||
// VBO for colorsArray
|
||||
glGenBuffers(1, &vboColorsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
|
@ -376,8 +395,9 @@ void VoxelSystem::init() {
|
|||
INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM,
|
||||
indicesArray, GL_STATIC_DRAW);
|
||||
|
||||
// delete the indices array that is no longer needed
|
||||
// delete the indices and normals arrays that are no longer needed
|
||||
delete[] indicesArray;
|
||||
delete[] normalsArray;
|
||||
}
|
||||
|
||||
void VoxelSystem::render() {
|
||||
|
@ -403,11 +423,15 @@ void VoxelSystem::render() {
|
|||
|
||||
// tell OpenGL where to find vertex and color information
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
|
||||
glNormalPointer(GL_FLOAT, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||
|
||||
|
@ -418,6 +442,7 @@ void VoxelSystem::render() {
|
|||
|
||||
// deactivate vertex and color arrays after drawing
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
// bind with 0 to switch back to normal operation
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <AgentData.h>
|
||||
#include <VoxelTree.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include "Head.h"
|
||||
#include "Avatar.h"
|
||||
#include "Util.h"
|
||||
#include "world.h"
|
||||
|
||||
|
@ -34,7 +34,7 @@ public:
|
|||
void render();
|
||||
void setVoxelsRendered(int v) {voxelsRendered = v;};
|
||||
int getVoxelsRendered() {return voxelsRendered;};
|
||||
void setViewerHead(Head *newViewerHead);
|
||||
void setViewerAvatar(Avatar *newViewerAvatar);
|
||||
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
|
||||
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer);
|
||||
|
||||
|
@ -67,7 +67,7 @@ private:
|
|||
static float _minDistance;
|
||||
|
||||
int voxelsRendered;
|
||||
Head *viewerHead;
|
||||
Avatar *viewerAvatar;
|
||||
VoxelTree *tree;
|
||||
GLfloat *readVerticesArray;
|
||||
GLubyte *readColorsArray;
|
||||
|
@ -76,6 +76,7 @@ private:
|
|||
GLubyte *writeColorsArray;
|
||||
GLfloat *writeVerticesEndPointer;
|
||||
GLuint vboVerticesID;
|
||||
GLuint vboNormalsID;
|
||||
GLuint vboColorsID;
|
||||
GLuint vboIndicesID;
|
||||
pthread_mutex_t bufferWriteLock;
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
#include "MenuColumn.h"
|
||||
#include "Menu.h"
|
||||
#include "Camera.h"
|
||||
#include "Head.h"
|
||||
#include "Avatar.h"
|
||||
#include "Particle.h"
|
||||
#include "Texture.h"
|
||||
#include "Cloud.h"
|
||||
|
@ -107,7 +107,7 @@ Oscilloscope audioScope(256,200,true);
|
|||
|
||||
ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||
|
||||
Head myAvatar(true); // The rendered avatar of oneself
|
||||
Avatar myAvatar(true); // The rendered avatar of oneself
|
||||
Camera myCamera; // My view onto the world (sometimes on myself :)
|
||||
Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
|
||||
|
||||
|
@ -157,9 +157,13 @@ VoxelDetail paintingVoxel; // The voxel we're painting if we're paintin
|
|||
unsigned char dominantColor = 0; // The dominant color of the voxel we're painting
|
||||
bool perfStatsOn = false; // Do we want to display perfStats?
|
||||
|
||||
bool logOn = true; // Whether to show on-screen log
|
||||
|
||||
int noiseOn = 0; // Whether to add random noise
|
||||
float noise = 1.0; // Overall magnitude scaling for random noise levels
|
||||
|
||||
bool gyroLook = false; // Whether to allow the gyro data from head to move your view
|
||||
|
||||
int displayLevels = 0;
|
||||
bool lookingInMirror = 0; // Are we currently rendering one's own head as if in mirror?
|
||||
int displayField = 0;
|
||||
|
@ -304,7 +308,7 @@ void displayStats(void)
|
|||
char legend2[] = "* - toggle stars, & - toggle paint mode, '-' - send erase all, '%' - send add scene";
|
||||
drawtext(10, statsVerticalOffset + 32, 0.10f, 0, 1.0, 0, legend2);
|
||||
|
||||
glm::vec3 avatarPos = myAvatar.getBodyPosition();
|
||||
glm::vec3 avatarPos = myAvatar.getPosition();
|
||||
|
||||
char stats[200];
|
||||
sprintf(stats, "FPS = %3.0f Pkts/s = %d Bytes/s = %d Head(x,y,z)= %4.2f, %4.2f, %4.2f ",
|
||||
|
@ -380,7 +384,7 @@ void initDisplay(void)
|
|||
void init(void)
|
||||
{
|
||||
voxels.init();
|
||||
voxels.setViewerHead(&myAvatar);
|
||||
voxels.setViewerAvatar(&myAvatar);
|
||||
myAvatar.setRenderYaw(startYaw);
|
||||
|
||||
initializeHandController();
|
||||
|
@ -396,8 +400,8 @@ void init(void)
|
|||
if (noiseOn) {
|
||||
myAvatar.setNoise(noise);
|
||||
}
|
||||
myAvatar.setBodyPosition(start_location);
|
||||
myCamera.setPosition( start_location );
|
||||
myAvatar.setPosition(start_location);
|
||||
myCamera.setPosition(start_location);
|
||||
|
||||
|
||||
#ifdef MARKER_CAPTURE
|
||||
|
@ -438,7 +442,7 @@ void reset_sensors()
|
|||
|
||||
renderYawRate = 0;
|
||||
renderPitchRate = 0;
|
||||
myAvatar.setBodyPosition(start_location);
|
||||
myAvatar.setPosition(start_location);
|
||||
headMouseX = WIDTH/2;
|
||||
headMouseY = HEIGHT/2;
|
||||
|
||||
|
@ -476,29 +480,14 @@ void updateAvatar(float frametime)
|
|||
headMouseY = min(headMouseY, HEIGHT);
|
||||
|
||||
// Update render direction (pitch/yaw) based on measured gyro rates
|
||||
const int MIN_YAW_RATE = 100;
|
||||
const int MIN_PITCH_RATE = 100;
|
||||
const float YAW_SENSITIVITY = 0.02;
|
||||
const float PITCH_SENSITIVITY = 0.05;
|
||||
const float MIN_YAW_RATE = 5;
|
||||
const float YAW_SENSITIVITY = 1.0;
|
||||
|
||||
// Update render pitch and yaw rates based on keyPositions
|
||||
const float KEY_YAW_SENSITIVITY = 2.0;
|
||||
if (myAvatar.getDriveKeys(ROT_LEFT)) renderYawRate -= KEY_YAW_SENSITIVITY*frametime;
|
||||
if (myAvatar.getDriveKeys(ROT_RIGHT)) renderYawRate += KEY_YAW_SENSITIVITY*frametime;
|
||||
|
||||
if (fabs(gyroYawRate) > MIN_YAW_RATE)
|
||||
{
|
||||
if (gyroYawRate > 0)
|
||||
renderYawRate += (gyroYawRate - MIN_YAW_RATE) * YAW_SENSITIVITY * frametime;
|
||||
else
|
||||
renderYawRate += (gyroYawRate + MIN_YAW_RATE) * YAW_SENSITIVITY * frametime;
|
||||
// If enabled, Update render pitch and yaw based on gyro data
|
||||
if (::gyroLook) {
|
||||
if (fabs(gyroYawRate) > MIN_YAW_RATE) {
|
||||
myAvatar.addBodyYaw(-gyroYawRate * YAW_SENSITIVITY * frametime);
|
||||
}
|
||||
if (fabs(gyroPitchRate) > MIN_PITCH_RATE)
|
||||
{
|
||||
if (gyroPitchRate > 0)
|
||||
renderPitchRate += (gyroPitchRate - MIN_PITCH_RATE) * PITCH_SENSITIVITY * frametime;
|
||||
else
|
||||
renderPitchRate += (gyroPitchRate + MIN_PITCH_RATE) * PITCH_SENSITIVITY * frametime;
|
||||
}
|
||||
|
||||
float renderPitch = myAvatar.getRenderPitch();
|
||||
|
@ -514,11 +503,8 @@ void updateAvatar(float frametime)
|
|||
myAvatar.setRenderPitch(renderPitch + renderPitchRate);
|
||||
|
||||
// Get audio loudness data from audio input device
|
||||
float loudness, averageLoudness;
|
||||
#ifndef _WIN32
|
||||
audio.getInputLoudness(&loudness, &averageLoudness);
|
||||
myAvatar.setLoudness(loudness);
|
||||
myAvatar.setAverageLoudness(averageLoudness);
|
||||
myAvatar.setLoudness(audio.getInputLoudness());
|
||||
#endif
|
||||
|
||||
// Update Avatar with latest camera and view frustum data...
|
||||
|
@ -551,7 +537,7 @@ void updateAvatar(float frametime)
|
|||
// If I'm in paint mode, send a voxel out to VOXEL server agents.
|
||||
if (::paintOn) {
|
||||
|
||||
glm::vec3 avatarPos = myAvatar.getBodyPosition();
|
||||
glm::vec3 avatarPos = myAvatar.getPosition();
|
||||
|
||||
// For some reason, we don't want to flip X and Z here.
|
||||
::paintingVoxel.x = avatarPos.x/10.0;
|
||||
|
@ -833,7 +819,7 @@ void display(void)
|
|||
//----------------------------------------------------
|
||||
// set the camera to third-person view behind my av
|
||||
//----------------------------------------------------
|
||||
myCamera.setTargetPosition ( myAvatar.getBodyPosition() );
|
||||
myCamera.setTargetPosition ( myAvatar.getPosition() );
|
||||
myCamera.setYaw ( 180.0 - myAvatar.getBodyYaw() );
|
||||
myCamera.setPitch ( 0.0 ); // temporarily, this must be 0.0 or else bad juju
|
||||
myCamera.setRoll ( 0.0 );
|
||||
|
@ -878,9 +864,10 @@ void display(void)
|
|||
if (::starsOn) {
|
||||
// should be the first rendering pass - w/o depth buffer / lighting
|
||||
|
||||
glm::mat4 view;
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
|
||||
stars.render(angleConvert<Degrees,Radians>(whichCamera.getFieldOfView()), aspectRatio, view);
|
||||
|
||||
// finally render the starfield
|
||||
stars.render(whichCamera.getFieldOfView(), aspectRatio, whichCamera.getNearClip());
|
||||
|
||||
}
|
||||
|
||||
glEnable(GL_LIGHTING);
|
||||
|
@ -927,7 +914,7 @@ void display(void)
|
|||
agent != agentList->getAgents().end();
|
||||
agent++) {
|
||||
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
Head *avatar = (Head *)agent->getLinkedData();
|
||||
Avatar *avatar = (Avatar *)agent->getLinkedData();
|
||||
avatar->render(0);
|
||||
}
|
||||
}
|
||||
|
@ -935,7 +922,7 @@ void display(void)
|
|||
if ( !::lookingInMirror ) balls.render();
|
||||
|
||||
// Render the world box
|
||||
if (!::lookingInMirror && statsOn) render_world_box();
|
||||
if (!::lookingInMirror && ::statsOn) { render_world_box(); }
|
||||
|
||||
// brad's frustum for debugging
|
||||
if (::frustumOn) renderViewFrustum(::viewFrustum);
|
||||
|
@ -977,13 +964,12 @@ void display(void)
|
|||
// Show detected levels from the serial I/O ADC channel sensors
|
||||
if (displayLevels) serialPort.renderLevels(WIDTH,HEIGHT);
|
||||
|
||||
// Display miscellaneous text stats onscreen
|
||||
if (statsOn) {
|
||||
// Display stats and log text onscreen
|
||||
glLineWidth(1.0f);
|
||||
glPointSize(1.0f);
|
||||
displayStats();
|
||||
logger.render(WIDTH, HEIGHT);
|
||||
}
|
||||
|
||||
if (::statsOn) { displayStats(); }
|
||||
if (::logOn) { logger.render(WIDTH, HEIGHT); }
|
||||
|
||||
// Show menu
|
||||
if (::menuOn) {
|
||||
|
@ -1072,6 +1058,16 @@ int setNoise(int state) {
|
|||
return iRet;
|
||||
}
|
||||
|
||||
int setLog(int state) {
|
||||
int iRet = setValue(state, &::logOn);
|
||||
return iRet;
|
||||
}
|
||||
|
||||
int setGyroLook(int state) {
|
||||
int iRet = setValue(state, &::gyroLook);
|
||||
return iRet;
|
||||
}
|
||||
|
||||
int setVoxels(int state) {
|
||||
return setValue(state, &::showingVoxels);
|
||||
}
|
||||
|
@ -1081,7 +1077,7 @@ int setStars(int state) {
|
|||
}
|
||||
|
||||
int setStats(int state) {
|
||||
return setValue(state, &statsOn);
|
||||
return setValue(state, &::statsOn);
|
||||
}
|
||||
|
||||
int setMenu(int state) {
|
||||
|
@ -1190,19 +1186,24 @@ const char* getFrustumRenderModeName(int state) {
|
|||
}
|
||||
|
||||
void initMenu() {
|
||||
MenuColumn *menuColumnOptions, *menuColumnTools, *menuColumnDebug, *menuColumnFrustum;
|
||||
MenuColumn *menuColumnOptions, *menuColumnRender, *menuColumnTools, *menuColumnDebug, *menuColumnFrustum;
|
||||
// Options
|
||||
menuColumnOptions = menu.addColumn("Options");
|
||||
menuColumnOptions->addRow("Mirror (h)", setHead);
|
||||
menuColumnOptions->addRow("Field (f)", setField);
|
||||
menuColumnOptions->addRow("(N)oise", setNoise);
|
||||
menuColumnOptions->addRow("(V)oxels", setVoxels);
|
||||
menuColumnOptions->addRow("Stars (*)", setStars);
|
||||
menuColumnOptions->addRow("(Q)uit", quitApp);
|
||||
menuColumnOptions->addRow("Noise (n)", setNoise);
|
||||
menuColumnOptions->addRow("Gyro Look", setGyroLook);
|
||||
menuColumnOptions->addRow("Quit (q)", quitApp);
|
||||
|
||||
// Render
|
||||
menuColumnRender = menu.addColumn("Render");
|
||||
menuColumnRender->addRow("Voxels (V)", setVoxels);
|
||||
menuColumnRender->addRow("Stars (*)", setStars);
|
||||
menuColumnRender->addRow("Field (f)", setField);
|
||||
|
||||
// Tools
|
||||
menuColumnTools = menu.addColumn("Tools");
|
||||
menuColumnTools->addRow("Stats (/)", setStats);
|
||||
menuColumnTools->addRow("Log ", setLog);
|
||||
menuColumnTools->addRow("(M)enu", setMenu);
|
||||
|
||||
// Frustum Options
|
||||
|
@ -1265,7 +1266,7 @@ void shiftPaintingColor()
|
|||
}
|
||||
|
||||
void setupPaintingVoxel() {
|
||||
glm::vec3 avatarPos = myAvatar.getBodyPosition();
|
||||
glm::vec3 avatarPos = myAvatar.getPosition();
|
||||
|
||||
::paintingVoxel.x = avatarPos.z/-10.0; // voxel space x is negative z head space
|
||||
::paintingVoxel.y = avatarPos.y/-10.0; // voxel space y is negative y head space
|
||||
|
@ -1360,7 +1361,7 @@ void key(unsigned char k, int x, int y)
|
|||
|
||||
// Process keypresses
|
||||
if (k == 'q' || k == 'Q') ::terminate();
|
||||
if (k == '/') statsOn = !statsOn; // toggle stats
|
||||
if (k == '/') ::statsOn = !::statsOn; // toggle stats
|
||||
if (k == '*') ::starsOn = !::starsOn; // toggle stars
|
||||
if (k == 'V' || k == 'v') ::showingVoxels = !::showingVoxels; // toggle voxels
|
||||
if (k == 'F') ::frustumOn = !::frustumOn; // toggle view frustum debugging
|
||||
|
@ -1494,13 +1495,13 @@ void idle(void) {
|
|||
//
|
||||
updateAvatar(deltaTime);
|
||||
|
||||
//loop through all the other avatars and simulate them.
|
||||
//loop through all the other avatars and simulate them...
|
||||
AgentList * agentList = AgentList::getInstance();
|
||||
for(std::vector<Agent>::iterator agent = agentList->getAgents().begin(); agent != agentList->getAgents().end(); agent++)
|
||||
{
|
||||
if (agent->getLinkedData() != NULL)
|
||||
{
|
||||
Head *avatar = (Head *)agent->getLinkedData();
|
||||
Avatar *avatar = (Avatar *)agent->getLinkedData();
|
||||
avatar->simulate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
@ -1512,7 +1513,6 @@ void idle(void) {
|
|||
|
||||
glutPostRedisplay();
|
||||
lastTimeIdle = check;
|
||||
|
||||
}
|
||||
|
||||
// Read serial data
|
||||
|
@ -1612,7 +1612,7 @@ void mouseoverFunc( int x, int y)
|
|||
|
||||
void attachNewHeadToAgent(Agent *newAgent) {
|
||||
if (newAgent->getLinkedData() == NULL) {
|
||||
newAgent->setLinkedData(new Head(false));
|
||||
newAgent->setLinkedData(new Avatar(false));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -130,17 +130,18 @@ namespace starfield {
|
|||
|
||||
float halfPersp = perspective * 0.5f;
|
||||
|
||||
// determine dimensions based on a sought screen diagonal
|
||||
//
|
||||
// ww + hh = dd
|
||||
// a = h / w => h = wa
|
||||
// ww + ww aa = dd
|
||||
// ww = dd / (1 + aa)
|
||||
float diag = 2.0f * std::sin(halfPersp);
|
||||
// define diagonal and near distance
|
||||
float halfDiag = std::sin(halfPersp);
|
||||
float nearClip = std::cos(halfPersp);
|
||||
|
||||
float hw = 0.5f * sqrt(diag * diag / (1.0f + aspect * aspect));
|
||||
float hh = hw * aspect;
|
||||
// determine half dimensions based on the screen diagonal
|
||||
//
|
||||
// ww + hh = dd
|
||||
// a = w / h => w = ha
|
||||
// hh + hh aa = dd
|
||||
// hh = dd / (1 + aa)
|
||||
float hh = sqrt(halfDiag * halfDiag / (1.0f + aspect * aspect));
|
||||
float hw = hh * aspect;
|
||||
|
||||
// cancel all translation
|
||||
mat4 matrix = orientation;
|
||||
|
@ -154,6 +155,9 @@ namespace starfield {
|
|||
float azimuth = atan2(ahead.x,-ahead.z) + Radians::pi();
|
||||
float altitude = atan2(-ahead.y, hypotf(ahead.x, ahead.z));
|
||||
angleHorizontalPolar<Radians>(azimuth, altitude);
|
||||
float const eps = 0.002f;
|
||||
altitude = glm::clamp(altitude,
|
||||
-Radians::halfPi() + eps, Radians::halfPi() - eps);
|
||||
#if STARFIELD_HEMISPHERE_ONLY
|
||||
altitude = std::max(0.0f, altitude);
|
||||
#endif
|
||||
|
@ -162,24 +166,25 @@ namespace starfield {
|
|||
|
||||
// printLog("Stars.cpp: starting on tile #%d\n", tileIndex);
|
||||
|
||||
|
||||
#if STARFIELD_DEBUG_CULLING
|
||||
mat4 matrix_debug = glm::translate(
|
||||
glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f),
|
||||
vec3(0.0f, 0.0f, -4.0f)) * glm::affineInverse(matrix);
|
||||
mat4 matrix_debug = glm::translate(glm::frustum(-hw, hw, -hh, hh, nearClip, 10.0f),
|
||||
vec3(0.0f, 0.0f, -4.0f)) *
|
||||
glm::affineInverse(matrix);
|
||||
#endif
|
||||
|
||||
matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f)
|
||||
* glm::affineInverse(matrix);
|
||||
matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) * glm::affineInverse(matrix);
|
||||
|
||||
this->_itrOutIndex = (unsigned*) _arrBatchOffs;
|
||||
this->_vecWxform = vec3(row(matrix, 3));
|
||||
this->_valHalfPersp = halfPersp;
|
||||
this->_valMinBright = minBright;
|
||||
|
||||
floodFill(_arrTile + tileIndex, TileSelection(*this,
|
||||
_arrTile, _arrTile + _objTiling.getTileCount(),
|
||||
(Tile**) _arrBatchCount));
|
||||
TileSelection::Cursor cursor;
|
||||
cursor.current = _arrTile + _objTiling.getTileIndex(azimuth, altitude);
|
||||
cursor.firstInRow = _arrTile + _objTiling.getTileIndex(0.0f, altitude);
|
||||
|
||||
floodFill(cursor, TileSelection(*this, _arrTile, _arrTile + _objTiling.getTileCount(),
|
||||
(TileSelection::Cursor*) _arrBatchCount));
|
||||
|
||||
#if STARFIELD_DEBUG_CULLING
|
||||
# define matrix matrix_debug
|
||||
|
@ -269,31 +274,35 @@ namespace starfield {
|
|||
|
||||
class TileSelection {
|
||||
|
||||
public:
|
||||
struct Cursor { Tile* current, * firstInRow; };
|
||||
private:
|
||||
Renderer& _refRenderer;
|
||||
Tile** const _arrStack;
|
||||
Tile** _itrStack;
|
||||
Cursor* const _arrStack;
|
||||
Cursor* _itrStack;
|
||||
Tile const* const _arrTile;
|
||||
Tile const* const _itrTilesEnd;
|
||||
Tile const* const _ptrTilesEnd;
|
||||
|
||||
public:
|
||||
|
||||
TileSelection(Renderer& renderer, Tile const* tiles,
|
||||
Tile const* tiles_end, Tile** stack) :
|
||||
Tile const* tiles_end, Cursor* stack) :
|
||||
|
||||
_refRenderer(renderer),
|
||||
_arrStack(stack),
|
||||
_itrStack(stack),
|
||||
_arrTile(tiles),
|
||||
_itrTilesEnd(tiles_end) {
|
||||
_ptrTilesEnd(tiles_end) {
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// flood fill strategy
|
||||
|
||||
bool select(Tile* t) {
|
||||
bool select(Cursor const& c) {
|
||||
Tile* t = c.current;
|
||||
|
||||
if (t < _arrTile || t >= _itrTilesEnd ||
|
||||
if (t < _arrTile || t >= _ptrTilesEnd ||
|
||||
!! (t->flags & Tile::checked)) {
|
||||
|
||||
// out of bounds or been here already
|
||||
|
@ -311,7 +320,8 @@ namespace starfield {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool process(Tile* t) {
|
||||
bool process(Cursor const& c) {
|
||||
Tile* t = c.current;
|
||||
|
||||
if (! (t->flags & Tile::visited)) {
|
||||
|
||||
|
@ -321,14 +331,39 @@ namespace starfield {
|
|||
return false;
|
||||
}
|
||||
|
||||
void right(Tile*& cursor) const { cursor += 1; }
|
||||
void left(Tile*& cursor) const { cursor -= 1; }
|
||||
void up(Tile*& cursor) const { cursor += yStride(); }
|
||||
void down(Tile*& cursor) const { cursor -= yStride(); }
|
||||
void right(Cursor& c) const {
|
||||
|
||||
void defer(Tile* t) { *_itrStack++ = t; }
|
||||
c.current += 1;
|
||||
if (c.current == c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles()) {
|
||||
c.current = c.firstInRow;
|
||||
}
|
||||
}
|
||||
void left(Cursor& c) const {
|
||||
|
||||
bool deferred(Tile*& cursor) {
|
||||
if (c.current == c.firstInRow) {
|
||||
c.current = c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles();
|
||||
}
|
||||
c.current -= 1;
|
||||
}
|
||||
void up(Cursor& c) const {
|
||||
|
||||
unsigned d = _refRenderer._objTiling.getAzimuthalTiles();
|
||||
c.current += d;
|
||||
c.firstInRow += d;
|
||||
}
|
||||
void down(Cursor& c) const {
|
||||
|
||||
unsigned d = _refRenderer._objTiling.getAzimuthalTiles();
|
||||
c.current -= d;
|
||||
c.firstInRow -= d;
|
||||
}
|
||||
|
||||
void defer(Cursor const& t) {
|
||||
|
||||
*_itrStack++ = t;
|
||||
}
|
||||
|
||||
bool deferred(Cursor& cursor) {
|
||||
|
||||
if (_itrStack != _arrStack) {
|
||||
cursor = *--_itrStack;
|
||||
|
@ -336,12 +371,6 @@ namespace starfield {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned yStride() const {
|
||||
|
||||
return _refRenderer._objTiling.getAzimuthalTiles();
|
||||
}
|
||||
};
|
||||
|
||||
bool visitTile(Tile* t) {
|
||||
|
@ -362,6 +391,7 @@ namespace starfield {
|
|||
bool tileVisible(Tile* t, unsigned i) {
|
||||
|
||||
float slice = _objTiling.getSliceAngle();
|
||||
float halfSlice = 0.5f * slice;
|
||||
unsigned stride = _objTiling.getAzimuthalTiles();
|
||||
float azimuth = (i % stride) * slice;
|
||||
float altitude = (i / stride) * slice - Radians::halfPi();
|
||||
|
@ -371,14 +401,13 @@ namespace starfield {
|
|||
vec3 tileCenter = vec3(gx * exz, sin(altitude), gz * exz);
|
||||
float w = dot(_vecWxform, tileCenter);
|
||||
|
||||
float halfSlice = 0.5f * slice;
|
||||
float daz = halfSlice * cos(abs(altitude) - halfSlice);
|
||||
float daz = halfSlice * cos(std::max(0.0f, abs(altitude) - halfSlice));
|
||||
float dal = halfSlice;
|
||||
float adjustedNear = cos(_valHalfPersp + sqrt(daz * daz + dal * dal));
|
||||
|
||||
// printLog("Stars.cpp: checking tile #%d, w = %f, near = %f\n", i, w, nearClip);
|
||||
|
||||
return w > adjustedNear;
|
||||
return w >= adjustedNear;
|
||||
}
|
||||
|
||||
void updateVertexCount(Tile* t, BrightnessLevel minBright) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// starfield/renderer/
|
||||
// starfield/renderer/Tiling.h
|
||||
// interface
|
||||
//
|
||||
// Created by Tobias Schwinger on 3/22/13.
|
||||
|
@ -51,6 +51,7 @@ namespace starfield {
|
|||
private:
|
||||
|
||||
unsigned discreteAngle(float unsigned_angle) const {
|
||||
|
||||
return unsigned(floor(unsigned_angle * _valRcpSlice + 0.5f));
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
|||
// and return the number of bytes to push the pointer
|
||||
|
||||
// Body world position
|
||||
memcpy(destinationBuffer, &_bodyPosition, sizeof(float) * 3);
|
||||
memcpy(destinationBuffer, &_position, sizeof(float) * 3);
|
||||
destinationBuffer += sizeof(float) * 3;
|
||||
|
||||
// Body rotation (NOTE: This needs to become a quaternion to save two bytes)
|
||||
|
@ -125,7 +125,7 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
unsigned char* startPosition = sourceBuffer;
|
||||
|
||||
// Body world position
|
||||
memcpy(&_bodyPosition, sourceBuffer, sizeof(float) * 3);
|
||||
memcpy(&_position, sourceBuffer, sizeof(float) * 3);
|
||||
sourceBuffer += sizeof(float) * 3;
|
||||
|
||||
// Body rotation (NOTE: This needs to become a quaternion to save two bytes)
|
||||
|
@ -171,14 +171,14 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
return sourceBuffer - startPosition;
|
||||
}
|
||||
|
||||
glm::vec3 AvatarData::getBodyPosition() {
|
||||
return glm::vec3(_bodyPosition.x,
|
||||
_bodyPosition.y,
|
||||
_bodyPosition.z);
|
||||
glm::vec3 AvatarData::getPosition() {
|
||||
return glm::vec3(_position.x,
|
||||
_position.y,
|
||||
_position.z);
|
||||
}
|
||||
|
||||
void AvatarData::setBodyPosition(glm::vec3 bodyPosition) {
|
||||
_bodyPosition = bodyPosition;
|
||||
void AvatarData::setPosition(glm::vec3 position) {
|
||||
_position = position;
|
||||
}
|
||||
|
||||
void AvatarData::setHandPosition(glm::vec3 handPosition) {
|
||||
|
|
|
@ -20,8 +20,8 @@ public:
|
|||
|
||||
AvatarData* clone() const;
|
||||
|
||||
glm::vec3 getBodyPosition();
|
||||
void setBodyPosition(glm::vec3 bodyPosition);
|
||||
glm::vec3 getPosition();
|
||||
void setPosition(glm::vec3 position);
|
||||
void setHandPosition(glm::vec3 handPosition);
|
||||
|
||||
int getBroadcastData(unsigned char* destinationBuffer);
|
||||
|
@ -39,20 +39,20 @@ public:
|
|||
void setHeadPitch(float p) {_headPitch = p; }
|
||||
void setHeadYaw(float y) {_headYaw = y; }
|
||||
void setHeadRoll(float r) {_headRoll = r; };
|
||||
const float getHeadPitch() const { return _headPitch; };
|
||||
const float getHeadYaw() const { return _headYaw; };
|
||||
const float getHeadRoll() const { return _headRoll; };
|
||||
float getHeadPitch() const { return _headPitch; };
|
||||
float getHeadYaw() const { return _headYaw; };
|
||||
float getHeadRoll() const { return _headRoll; };
|
||||
void addHeadPitch(float p) {_headPitch -= p; }
|
||||
void addHeadYaw(float y){_headYaw -= y; }
|
||||
void addHeadRoll(float r){_headRoll += r; }
|
||||
|
||||
// Hand State
|
||||
void setHandState(char s) { _handState = s; };
|
||||
const float getHandState() const {return _handState; };
|
||||
char getHandState() const {return _handState; };
|
||||
|
||||
// Instantaneous audio loudness to drive mouth/facial animation
|
||||
void setLoudness(float l) { _audioLoudness = l; };
|
||||
const float getLoudness() const {return _audioLoudness; };
|
||||
float getLoudness() const {return _audioLoudness; };
|
||||
|
||||
// getters for camera details
|
||||
const glm::vec3& getCameraPosition() const { return _cameraPosition; };
|
||||
|
@ -75,7 +75,7 @@ public:
|
|||
void setCameraFarClip(float farClip) { _cameraFarClip = farClip; }
|
||||
|
||||
protected:
|
||||
glm::vec3 _bodyPosition;
|
||||
glm::vec3 _position;
|
||||
glm::vec3 _handPosition;
|
||||
|
||||
// Body rotation
|
||||
|
|
|
@ -262,29 +262,18 @@ float Agent::getAverageKilobitsPerSecond() {
|
|||
|
||||
void Agent::printLog(Agent const& agent) {
|
||||
|
||||
sockaddr_in *agentPublicSocket = (sockaddr_in *) agent.publicSocket;
|
||||
sockaddr_in *agentLocalSocket = (sockaddr_in *) agent.localSocket;
|
||||
char publicAddressBuffer[16] = {'\0'};
|
||||
unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, agent.publicSocket);
|
||||
|
||||
const char* publicAddressString = (agentPublicSocket == NULL)
|
||||
? "Unknown"
|
||||
: inet_ntoa(agentPublicSocket->sin_addr);
|
||||
unsigned short publicAddressPort = (agentPublicSocket == NULL)
|
||||
? 0
|
||||
: ntohs(agentPublicSocket->sin_port);
|
||||
|
||||
const char* localAddressString = (agentLocalSocket == NULL)
|
||||
? "Unknown"
|
||||
: inet_ntoa(agentLocalSocket->sin_addr);
|
||||
unsigned short localAddressPort = (agentLocalSocket == NULL)
|
||||
? 0
|
||||
: ntohs(agentPublicSocket->sin_port);
|
||||
char localAddressBuffer[16] = {'\0'};
|
||||
unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, agent.localSocket);
|
||||
|
||||
::printLog("ID: %d T: %s (%c) PA: %s:%d LA: %s:%d\n",
|
||||
agent.agentId,
|
||||
agent.getTypeName(),
|
||||
agent.type,
|
||||
publicAddressString,
|
||||
publicAddressBuffer,
|
||||
publicAddressPort,
|
||||
localAddressString,
|
||||
localAddressBuffer,
|
||||
localAddressPort);
|
||||
}
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
using shared_lib::printLog;
|
||||
|
||||
const char SOLO_AGENT_TYPES_STRING[] = {
|
||||
const char SOLO_AGENT_TYPES[3] = {
|
||||
AGENT_TYPE_AVATAR_MIXER,
|
||||
AGENT_TYPE_AUDIO_MIXER,
|
||||
AGENT_TYPE_VOXEL
|
||||
|
@ -306,7 +306,7 @@ void AgentList::handlePingReply(sockaddr *agentAddress) {
|
|||
}
|
||||
|
||||
Agent* AgentList::soloAgentOfType(char agentType) {
|
||||
if (memchr(SOLO_AGENT_TYPES_STRING, agentType, 1)) {
|
||||
if (memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES)) != NULL) {
|
||||
for(std::vector<Agent>::iterator agent = agents.begin(); agent != agents.end(); agent++) {
|
||||
if (agent->getType() == agentType) {
|
||||
return &*agent;
|
||||
|
@ -428,7 +428,7 @@ void *checkInWithDomainServer(void *args) {
|
|||
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);
|
||||
printLog("Domain server: %s - %s\n", DOMAIN_HOSTNAME, DOMAIN_IP);
|
||||
|
||||
} else {
|
||||
printLog("Failed lookup domainserver\n");
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
const int MAX_PACKET_SIZE = 1500;
|
||||
const unsigned int AGENT_SOCKET_LISTEN_PORT = 40103;
|
||||
const int AGENT_SILENCE_THRESHOLD_USECS = 2 * 1000000;
|
||||
extern const char SOLO_AGENT_TYPES_STRING[];
|
||||
extern const char SOLO_AGENT_TYPES[3];
|
||||
|
||||
extern char DOMAIN_HOSTNAME[];
|
||||
extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup
|
||||
|
|
103
libraries/shared/src/AudioInjector.cpp
Normal file
103
libraries/shared/src/AudioInjector.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
//
|
||||
// AudioInjector.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 4/23/13.
|
||||
//
|
||||
//
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
#include "SharedUtil.h"
|
||||
#include "PacketHeaders.h"
|
||||
|
||||
#include "AudioInjector.h"
|
||||
|
||||
const int BUFFER_LENGTH_BYTES = 512;
|
||||
const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t);
|
||||
const float SAMPLE_RATE = 22050.0f;
|
||||
const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000;
|
||||
|
||||
AudioInjector::AudioInjector(const char* filename) :
|
||||
_numTotalBytesAudio(0),
|
||||
_bearing(0),
|
||||
_attenuationModifier(255)
|
||||
{
|
||||
_position[0] = 0.0f;
|
||||
_position[1] = 0.0f;
|
||||
_position[2] = 0.0f;
|
||||
|
||||
std::fstream sourceFile;
|
||||
|
||||
sourceFile.open(filename, std::ios::in | std::ios::binary);
|
||||
sourceFile.seekg(0, std::ios::end);
|
||||
|
||||
_numTotalBytesAudio = sourceFile.tellg();
|
||||
if (_numTotalBytesAudio == -1) {
|
||||
printf("Error reading audio data from file %s\n", filename);
|
||||
_audioSampleArray = NULL;
|
||||
} else {
|
||||
printf("Read %d bytes from audio file\n", _numTotalBytesAudio);
|
||||
sourceFile.seekg(0, std::ios::beg);
|
||||
long sizeOfShortArray = _numTotalBytesAudio / 2;
|
||||
_audioSampleArray = new int16_t[sizeOfShortArray];
|
||||
|
||||
sourceFile.read((char *)_audioSampleArray, _numTotalBytesAudio);
|
||||
}
|
||||
}
|
||||
|
||||
AudioInjector::~AudioInjector() {
|
||||
delete[] _audioSampleArray;
|
||||
}
|
||||
|
||||
void AudioInjector::setPosition(float* position) {
|
||||
_position[0] = position[0];
|
||||
_position[1] = position[1];
|
||||
_position[2] = position[2];
|
||||
}
|
||||
|
||||
void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) const {
|
||||
if (_audioSampleArray != NULL) {
|
||||
timeval startTime;
|
||||
|
||||
// one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte
|
||||
int leadingBytes = 1 + (sizeof(float) * 4) + 1;
|
||||
unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes];
|
||||
|
||||
dataPacket[0] = PACKET_HEADER_INJECT_AUDIO;
|
||||
unsigned char *currentPacketPtr = dataPacket + 1;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
memcpy(currentPacketPtr, &_position[i], sizeof(float));
|
||||
currentPacketPtr += sizeof(float);
|
||||
}
|
||||
|
||||
*currentPacketPtr = _attenuationModifier;
|
||||
currentPacketPtr++;
|
||||
|
||||
memcpy(currentPacketPtr, &_bearing, sizeof(float));
|
||||
currentPacketPtr += sizeof(float);
|
||||
|
||||
for (int i = 0; i < _numTotalBytesAudio; i += BUFFER_LENGTH_BYTES) {
|
||||
gettimeofday(&startTime, NULL);
|
||||
|
||||
int numBytesToCopy = BUFFER_LENGTH_BYTES;
|
||||
|
||||
if (_numTotalBytesAudio - i < BUFFER_LENGTH_BYTES) {
|
||||
numBytesToCopy = _numTotalBytesAudio - i;
|
||||
memset(currentPacketPtr + numBytesToCopy, 0, BUFFER_LENGTH_BYTES - numBytesToCopy);
|
||||
}
|
||||
|
||||
memcpy(currentPacketPtr, _audioSampleArray + (i / 2), numBytesToCopy);
|
||||
|
||||
injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket));
|
||||
|
||||
double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime));
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
libraries/shared/src/AudioInjector.h
Normal file
35
libraries/shared/src/AudioInjector.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// AudioInjector.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 4/23/13.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __hifi__AudioInjector__
|
||||
#define __hifi__AudioInjector__
|
||||
|
||||
#include <iostream>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "UDPSocket.h"
|
||||
|
||||
class AudioInjector {
|
||||
public:
|
||||
AudioInjector(const char* filename);
|
||||
~AudioInjector();
|
||||
|
||||
void setPosition(float* position);
|
||||
void setBearing(float bearing) { _bearing = bearing; }
|
||||
void setAttenuationModifier(unsigned char attenuationModifier) { _attenuationModifier = attenuationModifier; }
|
||||
|
||||
void injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) const;
|
||||
private:
|
||||
int16_t* _audioSampleArray;
|
||||
int _numTotalBytesAudio;
|
||||
float _position[3];
|
||||
float _bearing;
|
||||
unsigned char _attenuationModifier;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__AudioInjector__) */
|
|
@ -9,32 +9,31 @@
|
|||
#ifndef __hifi__FloodFill__
|
||||
#define __hifi__FloodFill__
|
||||
|
||||
/**
|
||||
* Line scanning, iterative flood fill algorithm.
|
||||
*
|
||||
* The strategy must obey the following contract:
|
||||
*
|
||||
* There is an associated cursor that represents a position on the image.
|
||||
* The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)'
|
||||
* move it.
|
||||
* The state of a cursor can be deferred to temporary storage (typically a
|
||||
* stack or a queue) using the 'defer(C const&)' member function.
|
||||
* Calling 'deferred(C&)' restores a cursor's state from temporary storage
|
||||
* and removes it there.
|
||||
* The 'select(C const&)' and 'process(C const&)' functions control the
|
||||
* algorithm. The former is called to determine where to go. It may be
|
||||
* called multiple times but does not have to (and should not) return
|
||||
* 'true' more than once for a pixel to be selected (will cause memory
|
||||
* overuse, otherwise). The latter will never be called for a given pixel
|
||||
* unless previously selected. It may be called multiple times, in which
|
||||
* case it should return 'true' upon successful processing and 'false'
|
||||
* when an already processed pixel has been visited.
|
||||
*
|
||||
* Note: The terms "image" and "pixel" are used for illustratory purposes
|
||||
* and mean "undirected graph with 4-connected 2D grid topology" and "node",
|
||||
* respectively.
|
||||
*
|
||||
*/
|
||||
//
|
||||
// Line scanning, iterative flood fill algorithm.
|
||||
//
|
||||
// The strategy must obey the following contract:
|
||||
//
|
||||
// There is an associated cursor that represents a position on the image.
|
||||
// The member functions 'left(C&)', 'right(C&)', 'up(C&)', and 'down(C&)'
|
||||
// move it.
|
||||
// The state of a cursor can be deferred to temporary storage (typically a
|
||||
// stack or a queue) using the 'defer(C const&)' member function.
|
||||
// Calling 'deferred(C&)' restores a cursor's state from temporary storage
|
||||
// and removes it there.
|
||||
// The 'select(C const&)' and 'process(C const&)' functions control the
|
||||
// algorithm. The former is called to determine where to go. It may be
|
||||
// called multiple times but does not have to (and should not) return
|
||||
// 'true' more than once for a pixel to be selected (will cause memory
|
||||
// overuse, otherwise). The latter will never be called for a given pixel
|
||||
// unless previously selected. It may be called multiple times, in which
|
||||
// case it should return 'true' upon successful processing and 'false'
|
||||
// when an already processed pixel has been visited.
|
||||
//
|
||||
// Note: The terms "image" and "pixel" are used for illustratory purposes
|
||||
// and mean "undirected graph with 4-connected 2D grid topology" and "node",
|
||||
// respectively.
|
||||
//
|
||||
template< class Strategy, typename Cursor >
|
||||
void floodFill(Cursor const& position,
|
||||
Strategy const& strategy = Strategy());
|
||||
|
@ -63,57 +62,39 @@ struct floodFill_impl : Strategy {
|
|||
}
|
||||
|
||||
Cursor higher, lower, h,l, i;
|
||||
bool higherFound, lowerFound, hf, lf;
|
||||
do {
|
||||
|
||||
if (! process(position)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
higher = position; higherFound = false;
|
||||
up(higher); yTest(higher, higherFound);
|
||||
lower = position; lowerFound = false;
|
||||
down(lower); yTest(lower, lowerFound);
|
||||
higher = position;
|
||||
up(higher);
|
||||
if (select(higher)) { defer(higher); }
|
||||
|
||||
lower = position;
|
||||
down(lower);
|
||||
if (select(lower)) { defer(lower); }
|
||||
|
||||
i = position, h = higher, l = lower;
|
||||
hf = higherFound, lf = lowerFound;
|
||||
do {
|
||||
right(i), right(h), right(l); yTest(h,hf); yTest(l,lf);
|
||||
|
||||
} while (selectAndProcess(i));
|
||||
right(i), right(h), right(l);
|
||||
if (select(h)) { defer(h); }
|
||||
if (select(l)) { defer(l); }
|
||||
|
||||
} while (select(i) && process(i));
|
||||
|
||||
i = position, h = higher, l = lower;
|
||||
hf = higherFound, lf = lowerFound;
|
||||
do {
|
||||
left(i); left(h); left(l); yTest(h,hf); yTest(l,lf);
|
||||
left(i); left(h); left(l);
|
||||
if (select(h)) { defer(h); }
|
||||
if (select(l)) { defer(l); }
|
||||
|
||||
} while (selectAndProcess(i));
|
||||
} while (select(i) && process(i));
|
||||
|
||||
} while (deferred(position));
|
||||
}
|
||||
|
||||
bool selectAndProcess(Cursor const& i) {
|
||||
|
||||
if (select(i)) {
|
||||
|
||||
process(i);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void yTest(Cursor const& i, bool& state) {
|
||||
|
||||
if (! select(i)) {
|
||||
|
||||
state = false;
|
||||
|
||||
} else if (! state) {
|
||||
|
||||
state = true;
|
||||
defer(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template< class Strategy, typename Cursor >
|
||||
|
|
|
@ -107,6 +107,18 @@ int getLocalAddress() {
|
|||
return localAddress;
|
||||
}
|
||||
|
||||
unsigned short loadBufferWithSocketInfo(char *addressBuffer, sockaddr *socket) {
|
||||
if (socket != NULL) {
|
||||
char *copyBuffer = inet_ntoa(((sockaddr_in*) socket)->sin_addr);
|
||||
memcpy(addressBuffer, copyBuffer, strlen(copyBuffer));
|
||||
return htons(((sockaddr_in*) socket)->sin_port);
|
||||
} else {
|
||||
const char* unknownAddress = "Unknown";
|
||||
memcpy(addressBuffer, unknownAddress, strlen(unknownAddress));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UDPSocket::UDPSocket(int listeningPort) {
|
||||
init();
|
||||
// create the socket
|
||||
|
|
|
@ -36,5 +36,6 @@ int packSocket(unsigned char *packStore, in_addr_t inAddress, in_port_t networkO
|
|||
int packSocket(unsigned char *packStore, sockaddr *socketToPack);
|
||||
int unpackSocket(unsigned char *packedData, sockaddr *unpackDestSocket);
|
||||
int getLocalAddress();
|
||||
unsigned short loadBufferWithSocketInfo(char *addressBuffer, sockaddr *socket);
|
||||
|
||||
#endif /* defined(__interface__UDPSocket__) */
|
||||
|
|
|
@ -19,7 +19,7 @@ VoxelAgentData::~VoxelAgentData() {
|
|||
}
|
||||
|
||||
VoxelAgentData::VoxelAgentData(const VoxelAgentData &otherAgentData) {
|
||||
memcpy(&_bodyPosition, &otherAgentData._bodyPosition, sizeof(_bodyPosition));
|
||||
memcpy(&_position, &otherAgentData._position, sizeof(_position));
|
||||
rootMarkerNode = new MarkerNode();
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,7 @@ void *distributeVoxelsToListeners(void *args) {
|
|||
stopOctal = randomTree.loadBitstreamBuffer(voxelPacketEnd,
|
||||
randomTree.rootNode,
|
||||
agentData->rootMarkerNode,
|
||||
agentData->getBodyPosition(),
|
||||
agentData->getPosition(),
|
||||
treeRoot,
|
||||
viewFrustum,
|
||||
::viewFrustumCulling,
|
||||
|
|
Loading…
Reference in a new issue