Conflicts:
	interface/src/main.cpp
This commit is contained in:
Andrzej Kapolka 2013-05-10 10:03:05 -07:00
commit beadb6a93d
26 changed files with 1049 additions and 793 deletions

View file

@ -71,23 +71,42 @@ void plateauAdditionOfSamples(int16_t &mixSample, int16_t sampleToAdd) {
mixSample = normalizedSample; mixSample = normalizedSample;
} }
void *sendBuffer(void *args) { void attachNewBufferToAgent(Agent *newAgent) {
int sentBytes; if (!newAgent->getLinkedData()) {
newAgent->setLinkedData(new AudioRingBuffer(RING_BUFFER_SAMPLES, BUFFER_LENGTH_SAMPLES_PER_CHANNEL));
}
}
int main(int argc, const char* argv[]) {
setvbuf(stdout, NULL, _IOLBF, 0);
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT);
ssize_t receivedBytes = 0;
agentList->linkedDataCreateCallback = attachNewBufferToAgent;
agentList->startSilentAgentRemovalThread();
agentList->startDomainServerCheckInThread();
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
sockaddr* agentAddress = new sockaddr;
// make sure our agent socket is non-blocking
agentList->getAgentSocket().setBlocking(false);
int nextFrame = 0; int nextFrame = 0;
timeval startTime; timeval startTime;
AgentList* agentList = AgentList::getInstance();
gettimeofday(&startTime, NULL); gettimeofday(&startTime, NULL);
while (true) { while (true) {
sentBytes = 0; // enumerate the agents, check if we can add audio from the agent to current mix
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
AudioRingBuffer* agentBuffer = (AudioRingBuffer*) agent->getLinkedData(); AudioRingBuffer* agentBuffer = (AudioRingBuffer*) agent->getLinkedData();
if (agentBuffer && agentBuffer->getEndOfLastWrite() != NULL) { if (agentBuffer->getEndOfLastWrite()) {
if (!agentBuffer->isStarted() if (!agentBuffer->isStarted()
&& agentBuffer->diffLastWriteNextOutput() <= BUFFER_LENGTH_SAMPLES_PER_CHANNEL + JITTER_BUFFER_SAMPLES) { && agentBuffer->diffLastWriteNextOutput() <= BUFFER_LENGTH_SAMPLES_PER_CHANNEL + JITTER_BUFFER_SAMPLES) {
printf("Held back buffer for agent with ID %d.\n", agent->getAgentId()); printf("Held back buffer for agent with ID %d.\n", agent->getAgentId());
@ -107,132 +126,131 @@ void *sendBuffer(void *args) {
int numAgents = agentList->size(); int numAgents = agentList->size();
float distanceCoefficients[numAgents][numAgents]; float distanceCoefficients[numAgents][numAgents];
memset(distanceCoefficients, 0, sizeof(distanceCoefficients)); memset(distanceCoefficients, 0, sizeof(distanceCoefficients));
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
AudioRingBuffer* agentRingBuffer = (AudioRingBuffer*) agent->getLinkedData(); AudioRingBuffer* agentRingBuffer = (AudioRingBuffer*) agent->getLinkedData();
int16_t clientMix[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2] = {};
if (agentRingBuffer) { for (AgentList::iterator otherAgent = agentList->begin(); otherAgent != agentList->end(); otherAgent++) {
int16_t clientMix[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2] = {}; if (otherAgent != agent || (otherAgent == agent && agentRingBuffer->shouldLoopbackForAgent())) {
AudioRingBuffer* otherAgentBuffer = (AudioRingBuffer*) otherAgent->getLinkedData();
for (AgentList::iterator otherAgent = agentList->begin(); otherAgent != agentList->end(); otherAgent++) {
if (otherAgent != agent || (otherAgent == agent && agentRingBuffer->shouldLoopbackForAgent())) { if (otherAgentBuffer->shouldBeAddedToMix()) {
AudioRingBuffer* otherAgentBuffer = (AudioRingBuffer*) otherAgent->getLinkedData();
if (otherAgentBuffer->shouldBeAddedToMix()) { float bearingRelativeAngleToSource = 0.f;
float attenuationCoefficient = 1.f;
int numSamplesDelay = 0;
float weakChannelAmplitudeRatio = 1.f;
if (otherAgent != agent) {
Position agentPosition = agentRingBuffer->getPosition();
Position otherAgentPosition = otherAgentBuffer->getPosition();
float bearingRelativeAngleToSource = 0.f; // calculate the distance to the other agent
float attenuationCoefficient = 1.f;
int numSamplesDelay = 0;
float weakChannelAmplitudeRatio = 1.f;
if (otherAgent != agent) { // use the distance to the other agent to calculate the change in volume for this frame
float *agentPosition = agentRingBuffer->getPosition(); int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex());
float *otherAgentPosition = otherAgentBuffer->getPosition(); int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex());
if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) {
float distanceToAgent = sqrtf(powf(agentPosition.x - otherAgentPosition.x, 2) +
powf(agentPosition.y - otherAgentPosition.y, 2) +
powf(agentPosition.z - otherAgentPosition.z, 2));
// calculate the distance to the other agent float minCoefficient = std::min(1.0f,
powf(0.5,
// use the distance to the other agent to calculate the change in volume for this frame (logf(DISTANCE_RATIO * distanceToAgent) / logf(3)) - 1));
int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex()); distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient;
int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex());
if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) {
float distanceToAgent = sqrtf(powf(agentPosition[0] - otherAgentPosition[0], 2) +
powf(agentPosition[1] - otherAgentPosition[1], 2) +
powf(agentPosition[2] - otherAgentPosition[2], 2));
float minCoefficient = std::min(1.0f,
powf(0.5,
(logf(DISTANCE_RATIO * distanceToAgent) / logf(3)) - 1));
distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient;
}
// get the angle from the right-angle triangle
float triangleAngle = atan2f(fabsf(agentPosition[2] - otherAgentPosition[2]),
fabsf(agentPosition[0] - otherAgentPosition[0])) * (180 / M_PI);
float absoluteAngleToSource = 0;
bearingRelativeAngleToSource = 0;
// find the angle we need for calculation based on the orientation of the triangle
if (otherAgentPosition[0] > agentPosition[0]) {
if (otherAgentPosition[2] > agentPosition[2]) {
absoluteAngleToSource = -90 + triangleAngle;
} else {
absoluteAngleToSource = -90 - triangleAngle;
}
} else {
if (otherAgentPosition[2] > agentPosition[2]) {
absoluteAngleToSource = 90 - triangleAngle;
} else {
absoluteAngleToSource = 90 + triangleAngle;
}
}
bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing();
if (bearingRelativeAngleToSource > 180) {
bearingRelativeAngleToSource -= 360;
} else if (bearingRelativeAngleToSource < -180) {
bearingRelativeAngleToSource += 360;
}
float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing();
if (angleOfDelivery > 180) {
angleOfDelivery -= 360;
} else if (angleOfDelivery < -180) {
angleOfDelivery += 360;
}
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f));
attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex]
* otherAgentBuffer->getAttenuationRatio()
* offAxisCoefficient;
bearingRelativeAngleToSource *= (M_PI / 180);
float sinRatio = fabsf(sinf(bearingRelativeAngleToSource));
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
} }
int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f
? clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
: clientMix;
int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f
? clientMix
: clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer() // get the angle from the right-angle triangle
float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z),
fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI);
float absoluteAngleToSource = 0;
bearingRelativeAngleToSource = 0;
// find the angle we need for calculation based on the orientation of the triangle
if (otherAgentPosition.x > agentPosition.x) {
if (otherAgentPosition.z > agentPosition.z) {
absoluteAngleToSource = -90 + triangleAngle;
} else {
absoluteAngleToSource = -90 - triangleAngle;
}
} else {
if (otherAgentPosition.z > agentPosition.z) {
absoluteAngleToSource = 90 - triangleAngle;
} else {
absoluteAngleToSource = 90 + triangleAngle;
}
}
bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing();
if (bearingRelativeAngleToSource > 180) {
bearingRelativeAngleToSource -= 360;
} else if (bearingRelativeAngleToSource < -180) {
bearingRelativeAngleToSource += 360;
}
float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing();
if (angleOfDelivery > 180) {
angleOfDelivery -= 360;
} else if (angleOfDelivery < -180) {
angleOfDelivery += 360;
}
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION +
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f));
attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex]
* otherAgentBuffer->getAttenuationRatio()
* offAxisCoefficient;
bearingRelativeAngleToSource *= (M_PI / 180);
float sinRatio = fabsf(sinf(bearingRelativeAngleToSource));
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
}
int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f
? clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
: clientMix;
int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f
? clientMix
: clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer()
? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay ? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay
: otherAgentBuffer->getNextOutput() - numSamplesDelay; : otherAgentBuffer->getNextOutput() - numSamplesDelay;
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { if (s < numSamplesDelay) {
// pull the earlier sample for the delayed channel
if (s < numSamplesDelay) { int earlierSample = delaySamplePointer[s] * attenuationCoefficient;
// pull the earlier sample for the delayed channel plateauAdditionOfSamples(delayedChannel[s], earlierSample * weakChannelAmplitudeRatio);
int earlierSample = delaySamplePointer[s] * attenuationCoefficient; }
plateauAdditionOfSamples(delayedChannel[s], earlierSample * weakChannelAmplitudeRatio);
} int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient);
plateauAdditionOfSamples(goodChannel[s], currentSample);
int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient);
plateauAdditionOfSamples(goodChannel[s], currentSample); if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay],
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { currentSample * weakChannelAmplitudeRatio);
plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay],
currentSample * weakChannelAmplitudeRatio);
}
} }
} }
} }
} }
}
agentList->getAgentSocket().send(agent->getPublicSocket(), clientMix, BUFFER_LENGTH_BYTES);
} agentList->getAgentSocket().send(agent->getPublicSocket(), clientMix, BUFFER_LENGTH_BYTES);
} }
// push forward the next output pointers for any audio buffers we used
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
AudioRingBuffer* agentBuffer = (AudioRingBuffer*) agent->getLinkedData(); AudioRingBuffer* agentBuffer = (AudioRingBuffer*) agent->getLinkedData();
if (agentBuffer && agentBuffer->shouldBeAddedToMix()) { if (agentBuffer && agentBuffer->shouldBeAddedToMix()) {
@ -246,45 +264,8 @@ void *sendBuffer(void *args) {
} }
} }
double usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); // pull any new audio data from agents off of the network stack
while (agentList->getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) {
if (usecToSleep > 0) {
usleep(usecToSleep);
} else {
std::cout << "Took too much time, not sleeping!\n";
}
}
pthread_exit(0);
}
void attachNewBufferToAgent(Agent *newAgent) {
if (newAgent->getLinkedData() == NULL) {
newAgent->setLinkedData(new AudioRingBuffer(RING_BUFFER_SAMPLES, BUFFER_LENGTH_SAMPLES_PER_CHANNEL));
}
}
int main(int argc, const char* argv[]) {
setvbuf(stdout, NULL, _IOLBF, 0);
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT);
ssize_t receivedBytes = 0;
agentList->linkedDataCreateCallback = attachNewBufferToAgent;
agentList->startSilentAgentRemovalThread();
agentList->startDomainServerCheckInThread();
unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE];
pthread_t sendBufferThread;
pthread_create(&sendBufferThread, NULL, sendBuffer, NULL);
sockaddr *agentAddress = new sockaddr;
while (true) {
if(agentList->getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) {
if (packetData[0] == PACKET_HEADER_INJECT_AUDIO) { if (packetData[0] == PACKET_HEADER_INJECT_AUDIO) {
if (agentList->addOrUpdateAgent(agentAddress, agentAddress, packetData[0], agentList->getLastAgentID())) { if (agentList->addOrUpdateAgent(agentAddress, agentAddress, packetData[0], agentList->getLastAgentID())) {
@ -294,9 +275,15 @@ int main(int argc, const char* argv[]) {
agentList->updateAgentWithData(agentAddress, packetData, receivedBytes); agentList->updateAgentWithData(agentAddress, packetData, receivedBytes);
} }
} }
double usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow();
if (usecToSleep > 0) {
usleep(usecToSleep);
} else {
std::cout << "Took too much time, not sleeping!\n";
}
} }
pthread_join(sendBufferThread, NULL);
return 0; return 0;
} }

View file

@ -29,7 +29,7 @@ const int ITERATIONS_BEFORE_HAND_GRAB = 100;
const int HAND_GRAB_DURATION_ITERATIONS = 50; const int HAND_GRAB_DURATION_ITERATIONS = 50;
const int HAND_TIMER_SLEEP_ITERATIONS = 50; const int HAND_TIMER_SLEEP_ITERATIONS = 50;
const float EVE_PELVIS_HEIGHT = 0.5f; const float EVE_PELVIS_HEIGHT = 0.565925f;
bool stopReceiveAgentDataThread; bool stopReceiveAgentDataThread;
bool injectAudioThreadRunning = false; bool injectAudioThreadRunning = false;

View file

@ -14,9 +14,9 @@ from random import random,randint
from math import sqrt, hypot, atan2, pi, fmod, degrees from math import sqrt, hypot, atan2, pi, fmod, degrees
from sys import argv,stderr from sys import argv,stderr
hemisphere_only, equator, meridians= False, 0, 1000 hemisphere_only, equator, meridians=False, 0, 1000
n_random = 100000 n_random = 50000
if len(argv) > 1: if len(argv) > 1:
n_random = int(argv[1]) n_random = int(argv[1])
@ -35,9 +35,9 @@ def meridian(azimuth,n,(r0,g0,b0),(r1,g1,b1)):
print "%f %f #%02x%02x%02x" % (azimuth,altitude,r,g,b) print "%f %f #%02x%02x%02x" % (azimuth,altitude,r,g,b)
print "%f %f #%02x%02x%02x" % (azimuth,-altitude,r,g,b) print "%f %f #%02x%02x%02x" % (azimuth,-altitude,r,g,b)
if meridians: #if meridians:
meridian( 0,meridians,(255,255,255), (180, 60,255)) # N->S #meridian( 0,meridians,(255,255,255), (180, 60,255)) # N->S
meridian(90,meridians,( 80,255, 80), (255,240, 40)) # E->W #meridian(90,meridians,( 80,255, 80), (255,240, 40)) # E->W
if equator: if equator:
azis = 360.0/equator azis = 360.0/equator

View file

@ -30,7 +30,7 @@ const float BODY_SPIN_FRICTION = 5.0;
const float BODY_UPRIGHT_FORCE = 10.0; const float BODY_UPRIGHT_FORCE = 10.0;
const float BODY_PITCH_WHILE_WALKING = 30.0; const float BODY_PITCH_WHILE_WALKING = 30.0;
const float BODY_ROLL_WHILE_TURNING = 0.1; const float BODY_ROLL_WHILE_TURNING = 0.1;
const float LIN_VEL_DECAY = 2.0; const float VELOCITY_DECAY = 5.0;
const float MY_HAND_HOLDING_PULL = 0.2; const float MY_HAND_HOLDING_PULL = 0.2;
const float YOUR_HAND_HOLDING_PULL = 1.0; const float YOUR_HAND_HOLDING_PULL = 1.0;
const float BODY_SPRING_DEFAULT_TIGHTNESS = 1500.0f; const float BODY_SPRING_DEFAULT_TIGHTNESS = 1500.0f;
@ -47,6 +47,8 @@ const float HEAD_MAX_PITCH = 45;
const float HEAD_MIN_PITCH = -45; const float HEAD_MIN_PITCH = -45;
const float HEAD_MAX_YAW = 85; const float HEAD_MAX_YAW = 85;
const float HEAD_MIN_YAW = -85; const float HEAD_MIN_YAW = -85;
const float AVATAR_BRAKING_RANGE = 1.6f;
const float AVATAR_BRAKING_STRENGTH = 30.0f;
float skinColor [] = {1.0, 0.84, 0.66}; float skinColor [] = {1.0, 0.84, 0.66};
float lightBlue [] = {0.7, 0.8, 1.0}; float lightBlue [] = {0.7, 0.8, 1.0};
@ -264,21 +266,15 @@ void Avatar::reset() {
// Update avatar head rotation with sensor data // Update avatar head rotation with sensor data
void Avatar::updateHeadFromGyros(float frametime, SerialInterface* serialInterface, glm::vec3* gravity) { void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterface, glm::vec3* gravity) {
float measuredPitchRate = 0.0f; float measuredPitchRate = 0.0f;
float measuredRollRate = 0.0f; float measuredRollRate = 0.0f;
float measuredYawRate = 0.0f; float measuredYawRate = 0.0f;
if (serialInterface->active && USING_INVENSENSE_MPU9150) { measuredPitchRate = serialInterface->getLastPitchRate();
measuredPitchRate = serialInterface->getLastPitchRate(); measuredYawRate = serialInterface->getLastYawRate();
measuredYawRate = serialInterface->getLastYawRate(); measuredRollRate = serialInterface->getLastRollRate();
measuredRollRate = serialInterface->getLastRollRate();
} else {
measuredPitchRate = serialInterface->getRelativeValue(HEAD_PITCH_RATE);
measuredYawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE);
measuredRollRate = serialInterface->getRelativeValue(HEAD_ROLL_RATE);
}
// Update avatar head position based on measured gyro rates // Update avatar head position based on measured gyro rates
const float MAX_PITCH = 45; const float MAX_PITCH = 45;
const float MIN_PITCH = -45; const float MIN_PITCH = -45;
@ -287,19 +283,44 @@ void Avatar::updateHeadFromGyros(float frametime, SerialInterface* serialInterfa
const float MAX_ROLL = 50; const float MAX_ROLL = 50;
const float MIN_ROLL = -50; const float MIN_ROLL = -50;
addHeadPitch(measuredPitchRate * frametime); addHeadPitch(measuredPitchRate * deltaTime);
addHeadYaw(measuredYawRate * frametime); addHeadYaw(measuredYawRate * deltaTime);
addHeadRoll(measuredRollRate * frametime); addHeadRoll(measuredRollRate * deltaTime);
setHeadPitch(glm::clamp(getHeadPitch(), MIN_PITCH, MAX_PITCH)); setHeadPitch(glm::clamp(getHeadPitch(), MIN_PITCH, MAX_PITCH));
setHeadYaw(glm::clamp(getHeadYaw(), MIN_YAW, MAX_YAW)); setHeadYaw(glm::clamp(getHeadYaw(), MIN_YAW, MAX_YAW));
setHeadRoll(glm::clamp(getHeadRoll(), MIN_ROLL, MAX_ROLL)); setHeadRoll(glm::clamp(getHeadRoll(), MIN_ROLL, MAX_ROLL));
// Update head lean distance based on accelerometer data
const float LEAN_SENSITIVITY = 0.15;
const float LEAN_MAX = 0.45;
const float LEAN_AVERAGING = 10.0;
glm::vec3 headRotationRates(getHeadPitch(), getHeadYaw(), getHeadRoll());
float headRateMax = 50.f;
glm::vec3 leaning = (serialInterface->getLastAcceleration() - serialInterface->getGravity())
* LEAN_SENSITIVITY
* (1.f - fminf(glm::length(headRotationRates), headRateMax) / headRateMax);
leaning.y = 0.f;
if (glm::length(leaning) < LEAN_MAX) {
_head.leanForward = _head.leanForward * (1.f - LEAN_AVERAGING * deltaTime) +
(LEAN_AVERAGING * deltaTime) * leaning.z * LEAN_SENSITIVITY;
_head.leanSideways = _head.leanSideways * (1.f - LEAN_AVERAGING * deltaTime) +
(LEAN_AVERAGING * deltaTime) * leaning.x * LEAN_SENSITIVITY;
}
setHeadLeanSideways(_head.leanSideways);
setHeadLeanForward(_head.leanForward);
} }
float Avatar::getAbsoluteHeadYaw() const { float Avatar::getAbsoluteHeadYaw() const {
return _bodyYaw + _headYaw; return _bodyYaw + _headYaw;
} }
float Avatar::getAbsoluteHeadPitch() const {
return _bodyPitch + _headPitch;
}
void Avatar::addLean(float x, float z) { void Avatar::addLean(float x, float z) {
//Add lean as impulse //Add lean as impulse
_head.leanSideways += x; _head.leanSideways += x;
@ -327,6 +348,8 @@ void Avatar::simulate(float deltaTime) {
// update balls // update balls
if (_balls) { _balls->simulate(deltaTime); } if (_balls) { _balls->simulate(deltaTime); }
// if other avatar, update head position from network data
// update avatar skeleton // update avatar skeleton
updateSkeleton(); updateSkeleton();
@ -403,23 +426,33 @@ void Avatar::simulate(float deltaTime) {
if (tiltDecay < 0.0f) {tiltDecay = 0.0f;} if (tiltDecay < 0.0f) {tiltDecay = 0.0f;}
_bodyPitch *= tiltDecay; _bodyPitch *= tiltDecay;
_bodyRoll *= tiltDecay; _bodyRoll *= tiltDecay;
//the following will be used to make the avatar upright no matter what gravity is
//float f = angleBetween(_orientation.getUp(), _gravity);
// update position by velocity // update position by velocity
_position += _velocity * deltaTime; _position += _velocity * deltaTime;
// decay velocity // decay velocity
_velocity *= (1.0 - LIN_VEL_DECAY * deltaTime); float decay = 1.0 - VELOCITY_DECAY * deltaTime;
if ( decay < 0.0 ) {
// If someone is near, damp velocity as a function of closeness _velocity = glm::vec3( 0.0f, 0.0f, 0.0f );
const float AVATAR_BRAKING_RANGE = 1.6f; } else {
const float AVATAR_BRAKING_STRENGTH = 35.f; _velocity *= decay;
if (_isMine && (_distanceToNearestAvatar < AVATAR_BRAKING_RANGE)) {
_velocity *=
(1.f - deltaTime * AVATAR_BRAKING_STRENGTH *
(AVATAR_BRAKING_RANGE - _distanceToNearestAvatar));
} }
// update head information // If another avatar is near, dampen velocity as a function of closeness
if (_isMine && (_distanceToNearestAvatar < AVATAR_BRAKING_RANGE)) {
float closeness = 1.0f - (_distanceToNearestAvatar / AVATAR_BRAKING_RANGE);
float drag = 1.0f - closeness * AVATAR_BRAKING_STRENGTH * deltaTime;
if ( drag > 0.0f ) {
_velocity *= drag;
} else {
_velocity = glm::vec3( 0.0f, 0.0f, 0.0f );
}
}
// update head state
updateHead(deltaTime); updateHead(deltaTime);
// use speed and angular velocity to determine walking vs. standing // use speed and angular velocity to determine walking vs. standing
@ -454,13 +487,10 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); Avatar *otherAvatar = (Avatar *)agent->getLinkedData();
/* //Test: Show angle between your fwd vector and nearest avatar
// Test: Show angle between your fwd vector and nearest avatar //glm::vec3 vectorBetweenUs = otherAvatar->getJointPosition(AVATAR_JOINT_PELVIS) -
glm::vec3 vectorBetweenUs = otherAvatar->getJointPosition(AVATAR_JOINT_PELVIS) - // getJointPosition(AVATAR_JOINT_PELVIS);
getJointPosition(AVATAR_JOINT_PELVIS); //printLog("Angle between: %f\n", angleBetween(vectorBetweenUs, _orientation.getFront()));
glm::vec3 myForwardVector = _orientation.getFront();
printLog("Angle between: %f\n", angleBetween(&vectorBetweenUs, &myForwardVector));
*/
// test whether shoulders are close enough to allow for reaching to touch hands // test whether shoulders are close enough to allow for reaching to touch hands
glm::vec3 v(_position - otherAvatar->_position); glm::vec3 v(_position - otherAvatar->_position);
@ -474,46 +504,105 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
if (_interactingOther) { if (_interactingOther) {
_avatarTouch.setYourBodyPosition(_interactingOther->_position); _avatarTouch.setYourBodyPosition(_interactingOther->_position);
_avatarTouch.setYourHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition); _avatarTouch.setYourHandPosition(_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition);
_avatarTouch.setYourHandState (_interactingOther->_handState); _avatarTouch.setYourHandState (_interactingOther->_handState);
//if hand-holding is initiated by either avatar, turn on hand-holding...
if (_avatarTouch.getHandsCloseEnoughToGrasp()) {
if ((_handState == HAND_STATE_GRASPING ) || (_interactingOther->_handState == HAND_STATE_GRASPING)) {
if (!_avatarTouch.getHoldingHands())
{
_avatarTouch.setHoldingHands(true);
}
}
}
if (!_avatarTouch.getAbleToReachOtherAvatar()) {
_avatarTouch.setHoldingHands(false);
}
if ((_handState != HAND_STATE_GRASPING ) && (_interactingOther->_handState != HAND_STATE_GRASPING)) {
_avatarTouch.setHoldingHands(false);
}
} }
//if holding hands, apply the appropriate forces
if (_avatarTouch.getHoldingHands()) {
glm::vec3 vectorToOtherHand = _interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition - _handHoldingPosition;
glm::vec3 vectorToMyHand = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - _handHoldingPosition;
float myInfluence = 30.0f;
float yourInfluence = 30.0f;
glm::vec3 myForce = vectorToMyHand * myInfluence * deltaTime;
glm::vec3 yourForce = vectorToOtherHand * yourInfluence * deltaTime;
if (_handState == HAND_STATE_GRASPING) {myForce *= 2.0f; }
if (_interactingOther->_handState == HAND_STATE_GRASPING) {yourForce *= 2.0f; }
_handHoldingPosition += myForce + yourForce;
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handHoldingPosition;
} else {
_handHoldingPosition = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position;
}
}//if (_isMine) }//if (_isMine)
//constrain right arm length and re-adjust elbow position as it bends //constrain right arm length and re-adjust elbow position as it bends
// NOTE - the following must be called on all avatars - not just _isMine // NOTE - the following must be called on all avatars - not just _isMine
updateArmIKAndConstraints(deltaTime); updateArmIKAndConstraints(deltaTime);
//Set right hand position and state to be transmitted, and also tell AvatarTouch about it
if (_isMine) { if (_isMine) {
//Set the vector we send for hand position to other people to be our right hand
setHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); setHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
if (_mousePressed) { if (_mousePressed) {
_handState = 1; _handState = HAND_STATE_GRASPING;
} else { } else {
_handState = 0; _handState = HAND_STATE_NULL;
} }
_avatarTouch.setMyHandState(_handState); _avatarTouch.setMyHandState(_handState);
_avatarTouch.setMyHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition);
if (_handState == 1) {
_avatarTouch.setMyHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition);
}
} }
} }
void Avatar::updateHead(float deltaTime) { void Avatar::updateHead(float deltaTime) {
// Get head position data from network for other people
if (!_isMine) {
_head.leanSideways = getHeadLeanSideways();
_head.leanForward = getHeadLeanForward();
}
//apply the head lean values to the springy position... //apply the head lean values to the springy position...
if (fabs(_head.leanSideways + _head.leanForward) > 0.0f) { if (fabs(_head.leanSideways + _head.leanForward) > 0.0f) {
glm::vec3 headLean = glm::vec3 headLean =
_orientation.getRight() * _head.leanSideways + _orientation.getRight() * _head.leanSideways +
_orientation.getFront() * _head.leanForward; _orientation.getFront() * _head.leanForward;
_joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition += headLean;
// this is not a long-term solution, but it works ok for initial purposes of making the avatar lean
_joint[ AVATAR_JOINT_TORSO ].springyPosition += headLean * 0.1f;
_joint[ AVATAR_JOINT_CHEST ].springyPosition += headLean * 0.4f;
_joint[ AVATAR_JOINT_NECK_BASE ].springyPosition += headLean * 0.7f;
_joint[ AVATAR_JOINT_HEAD_BASE ].springyPosition += headLean * 1.0f;
_joint[ AVATAR_JOINT_LEFT_COLLAR ].springyPosition += headLean * 0.6f;
_joint[ AVATAR_JOINT_LEFT_SHOULDER ].springyPosition += headLean * 0.6f;
_joint[ AVATAR_JOINT_LEFT_ELBOW ].springyPosition += headLean * 0.2f;
_joint[ AVATAR_JOINT_LEFT_WRIST ].springyPosition += headLean * 0.1f;
_joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].springyPosition += headLean * 0.0f;
_joint[ AVATAR_JOINT_RIGHT_COLLAR ].springyPosition += headLean * 0.6f;
_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].springyPosition += headLean * 0.6f;
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].springyPosition += headLean * 0.2f;
_joint[ AVATAR_JOINT_RIGHT_WRIST ].springyPosition += headLean * 0.1f;
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition += headLean * 0.0f;
} }
// Decay head back to center if turned on // Decay head back to center if turned on
if (_returnHeadToCenter) { if (_isMine && _returnHeadToCenter) {
// Decay back toward center // Decay back toward center
_headPitch *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime); _headPitch *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime);
_headYaw *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime); _headYaw *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime);
@ -521,15 +610,14 @@ void Avatar::updateHead(float deltaTime) {
} }
// For invensense gyro, decay only slightly when roughly centered // For invensense gyro, decay only slightly when roughly centered
if (USING_INVENSENSE_MPU9150) { if (_isMine) {
const float RETURN_RANGE = 5.0; const float RETURN_RANGE = 15.0;
const float RETURN_STRENGTH = 1.0; const float RETURN_STRENGTH = 2.0;
if (fabs(_headPitch) < RETURN_RANGE) { _headPitch *= (1.0f - RETURN_STRENGTH * deltaTime); } if (fabs(_headPitch) < RETURN_RANGE) { _headPitch *= (1.0f - RETURN_STRENGTH * deltaTime); }
if (fabs(_headYaw) < RETURN_RANGE) { _headYaw *= (1.0f - RETURN_STRENGTH * deltaTime); } if (fabs(_headYaw) < RETURN_RANGE) { _headYaw *= (1.0f - RETURN_STRENGTH * deltaTime); }
if (fabs(_headRoll) < RETURN_RANGE) { _headRoll *= (1.0f - RETURN_STRENGTH * deltaTime); } if (fabs(_headRoll) < RETURN_RANGE) { _headRoll *= (1.0f - RETURN_STRENGTH * deltaTime); }
} }
if (_head.noise) { if (_head.noise) {
// Move toward new target // Move toward new target
_headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; _headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ;
@ -618,9 +706,6 @@ void Avatar::updateHead(float deltaTime) {
} }
float Avatar::getHeight() { float Avatar::getHeight() {
return _height; return _height;
} }
@ -1083,54 +1168,62 @@ void Avatar::initializeSkeleton() {
_joint[ AVATAR_JOINT_RIGHT_TOES ].parent = AVATAR_JOINT_RIGHT_HEEL; _joint[ AVATAR_JOINT_RIGHT_TOES ].parent = AVATAR_JOINT_RIGHT_HEEL;
// specify the default pose position // specify the default pose position
_joint[ AVATAR_JOINT_PELVIS ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.0 ); _joint[ AVATAR_JOINT_PELVIS ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.0 );
_joint[ AVATAR_JOINT_TORSO ].defaultPosePosition = glm::vec3( 0.0, 0.08, 0.01 ); _joint[ AVATAR_JOINT_TORSO ].defaultPosePosition = glm::vec3( 0.0, 0.09, 0.01 );
_joint[ AVATAR_JOINT_CHEST ].defaultPosePosition = glm::vec3( 0.0, 0.09, 0.0 ); _joint[ AVATAR_JOINT_CHEST ].defaultPosePosition = glm::vec3( 0.0, 0.09, 0.01 );
_joint[ AVATAR_JOINT_NECK_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.1, -0.01 ); _joint[ AVATAR_JOINT_NECK_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.12, -0.01 );
_joint[ AVATAR_JOINT_HEAD_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.08, 0.01 ); _joint[ AVATAR_JOINT_HEAD_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.08, 0.00 );
_joint[ AVATAR_JOINT_LEFT_COLLAR ].defaultPosePosition = glm::vec3( -0.06, 0.04, -0.01 ); _joint[ AVATAR_JOINT_LEFT_COLLAR ].defaultPosePosition = glm::vec3( -0.06, 0.04, -0.01 );
_joint[ AVATAR_JOINT_LEFT_SHOULDER ].defaultPosePosition = glm::vec3( -0.03, 0.0, -0.01 ); _joint[ AVATAR_JOINT_LEFT_SHOULDER ].defaultPosePosition = glm::vec3( -0.05, 0.0, -0.01 );
_joint[ AVATAR_JOINT_LEFT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.13, 0.0 ); _joint[ AVATAR_JOINT_LEFT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 );
_joint[ AVATAR_JOINT_LEFT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.11, 0.0 ); _joint[ AVATAR_JOINT_LEFT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 );
_joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.07, 0.0 ); _joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 );
_joint[ AVATAR_JOINT_RIGHT_COLLAR ].defaultPosePosition = glm::vec3( 0.06, 0.04, -0.01 ); _joint[ AVATAR_JOINT_RIGHT_COLLAR ].defaultPosePosition = glm::vec3( 0.06, 0.04, -0.01 );
_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].defaultPosePosition = glm::vec3( 0.03, 0.0, -0.01 ); _joint[ AVATAR_JOINT_RIGHT_SHOULDER ].defaultPosePosition = glm::vec3( 0.05, 0.0, -0.01 );
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.13, 0.0 ); _joint[ AVATAR_JOINT_RIGHT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 );
_joint[ AVATAR_JOINT_RIGHT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.11, 0.0 ); _joint[ AVATAR_JOINT_RIGHT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 );
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.07, 0.0 ); _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 );
_joint[ AVATAR_JOINT_LEFT_HIP ].defaultPosePosition = glm::vec3( -0.04, 0.0, -0.02 );
_joint[ AVATAR_JOINT_LEFT_KNEE ].defaultPosePosition = glm::vec3( 0.0, -0.22, 0.02 ); _joint[ AVATAR_JOINT_LEFT_HIP ].defaultPosePosition = glm::vec3( -0.05, 0.0, -0.02 );
_joint[ AVATAR_JOINT_LEFT_HEEL ].defaultPosePosition = glm::vec3( 0.0, -0.22, -0.01 ); _joint[ AVATAR_JOINT_LEFT_KNEE ].defaultPosePosition = glm::vec3( 0.0, -0.27, 0.02 );
_joint[ AVATAR_JOINT_LEFT_HEEL ].defaultPosePosition = glm::vec3( 0.0, -0.27, -0.01 );
_joint[ AVATAR_JOINT_LEFT_TOES ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.05 ); _joint[ AVATAR_JOINT_LEFT_TOES ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.05 );
_joint[ AVATAR_JOINT_RIGHT_HIP ].defaultPosePosition = glm::vec3( 0.04, 0.0, -0.02 );
_joint[ AVATAR_JOINT_RIGHT_KNEE ].defaultPosePosition = glm::vec3( 0.0, -0.22, 0.02 ); _joint[ AVATAR_JOINT_RIGHT_HIP ].defaultPosePosition = glm::vec3( 0.05, 0.0, -0.02 );
_joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( 0.0, -0.22, -0.01 ); _joint[ AVATAR_JOINT_RIGHT_KNEE ].defaultPosePosition = glm::vec3( 0.0, -0.27, 0.02 );
_joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( 0.0, -0.27, -0.01 );
_joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.05 ); _joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.05 );
// specify the radii of the bone positions // specify the radii of the joints
_joint[ AVATAR_JOINT_PELVIS ].radius = 0.06; _joint[ AVATAR_JOINT_PELVIS ].radius = 0.07;
_joint[ AVATAR_JOINT_TORSO ].radius = 0.055; _joint[ AVATAR_JOINT_TORSO ].radius = 0.065;
_joint[ AVATAR_JOINT_CHEST ].radius = 0.075; _joint[ AVATAR_JOINT_CHEST ].radius = 0.08;
_joint[ AVATAR_JOINT_NECK_BASE ].radius = 0.03; _joint[ AVATAR_JOINT_NECK_BASE ].radius = 0.03;
_joint[ AVATAR_JOINT_HEAD_BASE ].radius = 0.07; _joint[ AVATAR_JOINT_HEAD_BASE ].radius = 0.07;
_joint[ AVATAR_JOINT_LEFT_COLLAR ].radius = 0.029;
_joint[ AVATAR_JOINT_LEFT_SHOULDER ].radius = 0.023; _joint[ AVATAR_JOINT_LEFT_COLLAR ].radius = 0.04;
_joint[ AVATAR_JOINT_LEFT_ELBOW ].radius = 0.017; _joint[ AVATAR_JOINT_LEFT_SHOULDER ].radius = 0.03;
_joint[ AVATAR_JOINT_LEFT_WRIST ].radius = 0.017; _joint[ AVATAR_JOINT_LEFT_ELBOW ].radius = 0.02;
_joint[ AVATAR_JOINT_LEFT_WRIST ].radius = 0.02;
_joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].radius = 0.01; _joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].radius = 0.01;
_joint[ AVATAR_JOINT_RIGHT_COLLAR ].radius = 0.029;
_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].radius = 0.023; _joint[ AVATAR_JOINT_RIGHT_COLLAR ].radius = 0.04;
_joint[ AVATAR_JOINT_RIGHT_ELBOW ].radius = 0.015; _joint[ AVATAR_JOINT_RIGHT_SHOULDER ].radius = 0.03;
_joint[ AVATAR_JOINT_RIGHT_WRIST ].radius = 0.015; _joint[ AVATAR_JOINT_RIGHT_ELBOW ].radius = 0.02;
_joint[ AVATAR_JOINT_RIGHT_WRIST ].radius = 0.02;
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].radius = 0.01; _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].radius = 0.01;
_joint[ AVATAR_JOINT_LEFT_HIP ].radius = 0.03;
_joint[ AVATAR_JOINT_LEFT_KNEE ].radius = 0.02; _joint[ AVATAR_JOINT_LEFT_HIP ].radius = 0.04;
_joint[ AVATAR_JOINT_LEFT_HEEL ].radius = 0.015; _joint[ AVATAR_JOINT_LEFT_KNEE ].radius = 0.025;
_joint[ AVATAR_JOINT_LEFT_TOES ].radius = 0.02; _joint[ AVATAR_JOINT_LEFT_HEEL ].radius = 0.025;
_joint[ AVATAR_JOINT_RIGHT_HIP ].radius = 0.03; _joint[ AVATAR_JOINT_LEFT_TOES ].radius = 0.027;
_joint[ AVATAR_JOINT_RIGHT_KNEE ].radius = 0.02;
_joint[ AVATAR_JOINT_RIGHT_HEEL ].radius = 0.015; _joint[ AVATAR_JOINT_RIGHT_HIP ].radius = 0.04;
_joint[ AVATAR_JOINT_RIGHT_TOES ].radius = 0.02; _joint[ AVATAR_JOINT_RIGHT_KNEE ].radius = 0.025;
_joint[ AVATAR_JOINT_RIGHT_HEEL ].radius = 0.025;
_joint[ AVATAR_JOINT_RIGHT_TOES ].radius = 0.027;
// specify the tightness of the springy positions as far as attraction to rigid body // specify the tightness of the springy positions as far as attraction to rigid body
_joint[ AVATAR_JOINT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 1.0; _joint[ AVATAR_JOINT_PELVIS ].springBodyTightness = BODY_SPRING_DEFAULT_TIGHTNESS * 1.0;
@ -1169,6 +1262,7 @@ void Avatar::initializeSkeleton() {
_joint[ AVATAR_JOINT_LEFT_HEEL ].radius + _joint[ AVATAR_JOINT_LEFT_HEEL ].radius +
_joint[ AVATAR_JOINT_LEFT_HEEL ].length + _joint[ AVATAR_JOINT_LEFT_HEEL ].length +
_joint[ AVATAR_JOINT_LEFT_KNEE ].length; _joint[ AVATAR_JOINT_LEFT_KNEE ].length;
printf("_pelvisStandingHeight = %f\n", _pelvisStandingHeight);
_height = _height =
( (
@ -1183,11 +1277,11 @@ void Avatar::initializeSkeleton() {
_joint[ AVATAR_JOINT_HEAD_BASE ].length + _joint[ AVATAR_JOINT_HEAD_BASE ].length +
_joint[ AVATAR_JOINT_HEAD_BASE ].radius _joint[ AVATAR_JOINT_HEAD_BASE ].radius
); );
//printf("_height = %f\n", _height); printf("_height = %f\n", _height);
// generate world positions // generate joint positions by updating the skeleton
updateSkeleton(); updateSkeleton();
//set spring positions to be in the skeleton bone positions //set spring positions to be in the skeleton bone positions
initializeBodySprings(); initializeBodySprings();
} }

View file

@ -98,6 +98,7 @@ public:
bool getIsNearInteractingOther(); bool getIsNearInteractingOther();
float getAbsoluteHeadYaw() const; float getAbsoluteHeadYaw() const;
float getAbsoluteHeadPitch() const;
void setLeanForward(float dist); void setLeanForward(float dist);
void setLeanSideways(float dist); void setLeanSideways(float dist);
void addLean(float x, float z); void addLean(float x, float z);

View file

@ -13,16 +13,19 @@
#include "Util.h" #include "Util.h"
const float THREAD_RADIUS = 0.012; const float THREAD_RADIUS = 0.012;
const float HANDS_CLOSE_ENOUGH_TO_GRASP = 0.1;
AvatarTouch::AvatarTouch() { AvatarTouch::AvatarTouch() {
_myHandPosition = glm::vec3(0.0f, 0.0f, 0.0f); _myHandPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_yourHandPosition = glm::vec3(0.0f, 0.0f, 0.0f); _yourHandPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_myBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f); _myBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_yourBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f); _yourBodyPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_myHandState = 0; _vectorBetweenHands = glm::vec3(0.0f, 0.0f, 0.0f);
_yourHandState = 0; _myHandState = HAND_STATE_NULL;
_reachableRadius = 0.0f; _yourHandState = HAND_STATE_NULL;
_reachableRadius = 0.0f;
_weAreHoldingHands = false;
_canReachToOtherAvatar = false; _canReachToOtherAvatar = false;
_handsCloseEnoughToGrasp = false; _handsCloseEnoughToGrasp = false;
@ -61,17 +64,62 @@ void AvatarTouch::setReachableRadius(float r) {
} }
void AvatarTouch::simulate (float deltaTime) {
glm::vec3 vectorBetweenBodies = _yourBodyPosition - _myBodyPosition;
float distanceBetweenBodies = glm::length(vectorBetweenBodies);
if (distanceBetweenBodies < _reachableRadius) {
_vectorBetweenHands = _yourHandPosition - _myHandPosition;
float distanceBetweenHands = glm::length(_vectorBetweenHands);
if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) {
_handsCloseEnoughToGrasp = true;
} else {
_handsCloseEnoughToGrasp = false;
}
_canReachToOtherAvatar = true;
} else {
_canReachToOtherAvatar = false;
}
}
void AvatarTouch::render(glm::vec3 cameraPosition) { void AvatarTouch::render(glm::vec3 cameraPosition) {
if (_canReachToOtherAvatar) { if (_canReachToOtherAvatar) {
//show circle indicating that we can reach out to each other...
glColor4f(0.3, 0.4, 0.5, 0.5); glColor4f(0.3, 0.4, 0.5, 0.5);
glm::vec3 p(_yourBodyPosition); glm::vec3 p(_yourBodyPosition);
p.y = 0.0005f; p.y = 0.0005f;
renderCircle(p, _reachableRadius, glm::vec3(0.0f, 1.0f, 0.0f), 30); renderCircle(p, _reachableRadius, glm::vec3(0.0f, 1.0f, 0.0f), 30);
// show is we are golding hands...
if (_weAreHoldingHands) {
glColor4f(0.9, 0.3, 0.3, 0.5);
renderSphereOutline(_myHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.3f, 20, cameraPosition);
renderSphereOutline(_myHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.2f, 20, cameraPosition);
renderSphereOutline(_myHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.1f, 20, cameraPosition);
renderSphereOutline(_yourHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.3f, 20, cameraPosition);
renderSphereOutline(_yourHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.2f, 20, cameraPosition);
renderSphereOutline(_yourHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP * 0.1f, 20, cameraPosition);
}
//render the beam between our hands indicting that we can reach out and grasp hands...
renderBeamBetweenHands();
//show that our hands are close enough to grasp..
if (_handsCloseEnoughToGrasp) {
glColor4f(0.9, 0.3, 0.3, 0.5);
renderSphereOutline(_myHandPosition, HANDS_CLOSE_ENOUGH_TO_GRASP / 3.0f, 20, cameraPosition);
}
// if your hand is grasping, show it... // if your hand is grasping, show it...
if (_yourHandState == 1) { if (_yourHandState == HAND_STATE_GRASPING) {
glPushMatrix(); glPushMatrix();
glTranslatef(_yourHandPosition.x, _yourHandPosition.y, _yourHandPosition.z); glTranslatef(_yourHandPosition.x, _yourHandPosition.y, _yourHandPosition.z);
glColor4f(1.0, 1.0, 0.8, 0.3); glutSolidSphere(0.020f, 10.0f, 10.0f); glColor4f(1.0, 1.0, 0.8, 0.3); glutSolidSphere(0.020f, 10.0f, 10.0f);
@ -79,31 +127,10 @@ void AvatarTouch::render(glm::vec3 cameraPosition) {
glColor4f(1.0, 1.0, 0.2, 0.1); glutSolidSphere(0.030f, 10.0f, 10.0f); glColor4f(1.0, 1.0, 0.2, 0.1); glutSolidSphere(0.030f, 10.0f, 10.0f);
glPopMatrix(); glPopMatrix();
} }
}
//show beam
glm::vec3 v1(_myHandPosition);
glm::vec3 v2(_yourHandPosition);
if (_handsCloseEnoughToGrasp) {
glLineWidth(2.0);
glColor4f(0.7f, 0.4f, 0.1f, 0.3);
glBegin(GL_LINE_STRIP);
glVertex3f(v1.x, v1.y, v1.z);
glVertex3f(v2.x, v2.y, v2.z);
glEnd();
glColor4f(1.0f, 1.0f, 0.0f, 0.8);
for (int p=0; p<NUM_POINTS; p++) {
glBegin(GL_POINTS);
glVertex3f(_point[p].x, _point[p].y, _point[p].z);
glEnd();
}
}
}
// if my hand is grasping, show it... // if my hand is grasping, show it...
if (_myHandState == 1) { if (_myHandState == HAND_STATE_GRASPING) {
glPushMatrix(); glPushMatrix();
glTranslatef(_myHandPosition.x, _myHandPosition.y, _myHandPosition.z); glTranslatef(_myHandPosition.x, _myHandPosition.y, _myHandPosition.z);
glColor4f(1.0, 1.0, 0.8, 0.3); glutSolidSphere(0.020f, 10.0f, 10.0f); glColor4f(1.0, 1.0, 0.8, 0.3); glutSolidSphere(0.020f, 10.0f, 10.0f);
@ -114,26 +141,32 @@ void AvatarTouch::render(glm::vec3 cameraPosition) {
} }
void AvatarTouch::simulate (float deltaTime) {
void AvatarTouch::renderBeamBetweenHands() {
glm::vec3 v = _yourBodyPosition - _myBodyPosition; glm::vec3 v1(_myHandPosition);
glm::vec3 v2(_yourHandPosition);
float distance = glm::length(v); glLineWidth(2.0);
glColor4f(0.9f, 0.9f, 0.1f, 0.7);
if (distance < _reachableRadius) { glBegin(GL_LINE_STRIP);
_canReachToOtherAvatar = true; glVertex3f(v1.x, v1.y, v1.z);
} else { glVertex3f(v2.x, v2.y, v2.z);
_canReachToOtherAvatar = false; glEnd();
}
/*
glColor3f(1.0f, 1.0f, 1.0f);
for (int p=0; p<NUM_POINTS; p++) { for (int p=0; p<NUM_POINTS; p++) {
_point[p] = _myHandPosition + v * ((float)p / (float)NUM_POINTS);
_point[p] = _myHandPosition + _vectorBetweenHands * ((float)p / (float)NUM_POINTS);
_point[p].x += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS); _point[p].x += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS);
_point[p].y += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS); _point[p].y += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS);
_point[p].z += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS); _point[p].z += randFloatInRange(-THREAD_RADIUS, THREAD_RADIUS);
}
*/ glBegin(GL_POINTS);
glVertex3f(_point[p].x, _point[p].y, _point[p].z);
} glEnd();
}
}

View file

@ -11,7 +11,14 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
const float HANDS_CLOSE_ENOUGH_TO_GRASP = 0.1; enum AvatarHandState
{
HAND_STATE_NULL = -1,
HAND_STATE_OPEN,
HAND_STATE_GRASPING,
HAND_STATE_POINTING,
NUM_HAND_STATES
};
class AvatarTouch { class AvatarTouch {
public: public:
@ -28,26 +35,33 @@ public:
void setMyHandState (int state); void setMyHandState (int state);
void setYourHandState (int state); void setYourHandState (int state);
void setReachableRadius (float r); void setReachableRadius (float r);
void setAbleToReachOtherAvatar (bool a) {_canReachToOtherAvatar = a;} void setAbleToReachOtherAvatar (bool a) {_canReachToOtherAvatar = a;}
void setHandsCloseEnoughToGrasp(bool h) {_handsCloseEnoughToGrasp = h;} void setHandsCloseEnoughToGrasp(bool h) {_handsCloseEnoughToGrasp = h;}
void setHoldingHands (bool h) {_weAreHoldingHands = h;}
bool getAbleToReachOtherAvatar () const {return _canReachToOtherAvatar;} bool getAbleToReachOtherAvatar () const {return _canReachToOtherAvatar; }
bool getHandsCloseEnoughToGrasp() const {return _handsCloseEnoughToGrasp;} bool getHandsCloseEnoughToGrasp() const {return _handsCloseEnoughToGrasp;}
bool getHoldingHands () const {return _weAreHoldingHands; }
private: private:
static const int NUM_POINTS = 100; static const int NUM_POINTS = 100;
bool _weAreHoldingHands;
glm::vec3 _point [NUM_POINTS]; glm::vec3 _point [NUM_POINTS];
glm::vec3 _myBodyPosition; glm::vec3 _myBodyPosition;
glm::vec3 _yourBodyPosition; glm::vec3 _yourBodyPosition;
glm::vec3 _myHandPosition; glm::vec3 _myHandPosition;
glm::vec3 _yourHandPosition; glm::vec3 _yourHandPosition;
glm::vec3 _vectorBetweenHands;
int _myHandState; int _myHandState;
int _yourHandState; int _yourHandState;
bool _canReachToOtherAvatar; bool _canReachToOtherAvatar;
bool _handsCloseEnoughToGrasp; bool _handsCloseEnoughToGrasp;
float _reachableRadius; float _reachableRadius;
void renderBeamBetweenHands();
}; };
#endif #endif

View file

@ -13,23 +13,25 @@
Camera::Camera() { Camera::Camera() {
_frustumNeedsReshape = false; _frustumNeedsReshape = false;
_mode = CAMERA_MODE_THIRD_PERSON; _mode = CAMERA_MODE_THIRD_PERSON;
_tightness = 10.0; // default _tightness = 10.0; // default
_fieldOfView = 60.0; // default _fieldOfView = 60.0; // default
_nearClip = 0.08; // default _nearClip = 0.08; // default
_farClip = 50.0 * TREE_SCALE; // default _farClip = 50.0 * TREE_SCALE; // default
_modeShift = 0.0; _modeShift = 0.0;
_yaw = 0.0; _yaw = 0.0;
_pitch = 0.0; _pitch = 0.0;
_roll = 0.0; _roll = 0.0;
_upShift = 0.0; _upShift = 0.0;
_rightShift = 0.0; _rightShift = 0.0;
_distance = 0.0; _distance = 0.0;
_idealYaw = 0.0; _idealYaw = 0.0;
_targetPosition = glm::vec3(0.0, 0.0, 0.0); _idealPitch = 0.0;
_position = glm::vec3(0.0, 0.0, 0.0); _idealRoll = 0.0;
_idealPosition = glm::vec3(0.0, 0.0, 0.0); _targetPosition = glm::vec3(0.0, 0.0, 0.0);
_orientation.setToIdentity(); _position = glm::vec3(0.0, 0.0, 0.0);
_idealPosition = glm::vec3(0.0, 0.0, 0.0);
_orientation.setToIdentity();
} }
@ -38,7 +40,7 @@ void Camera::update(float deltaTime) {
if (_mode == CAMERA_MODE_NULL) { if (_mode == CAMERA_MODE_NULL) {
_modeShift = 0.0; _modeShift = 0.0;
} else { } else {
// use iterative forces to keep the camera at the desired position and angle // use iterative forces to push the camera towards the desired position and angle
updateFollowMode(deltaTime); updateFollowMode(deltaTime);
if (_modeShift < 1.0f) { if (_modeShift < 1.0f) {
@ -70,8 +72,13 @@ void Camera::updateFollowMode(float deltaTime) {
} }
// update _yaw (before position!) // update _yaw (before position!)
_yaw += (_idealYaw - _yaw) * t; _yaw += (_idealYaw - _yaw ) * t;
_orientation.yaw(_yaw); _pitch += (_idealPitch - _pitch) * t;
_roll += (_idealRoll - _roll ) * t;
_orientation.yaw (_yaw );
_orientation.pitch(_pitch);
_orientation.roll (_roll );
float radian = (_yaw / 180.0) * PIE; float radian = (_yaw / 180.0) * PIE;
@ -91,6 +98,12 @@ void Camera::setMode(CameraMode m) {
_modeShift = 0.0f; _modeShift = 0.0f;
} }
void Camera::setTargetRotation( float yaw, float pitch, float roll ) {
_idealYaw = yaw;
_idealPitch = pitch;
_idealRoll = roll;
}
void Camera::setFieldOfView(float f) { void Camera::setFieldOfView(float f) {
_fieldOfView = f; _fieldOfView = f;
_frustumNeedsReshape = true; _frustumNeedsReshape = true;

View file

@ -16,7 +16,7 @@ enum CameraMode
CAMERA_MODE_NULL = -1, CAMERA_MODE_NULL = -1,
CAMERA_MODE_THIRD_PERSON, CAMERA_MODE_THIRD_PERSON,
CAMERA_MODE_FIRST_PERSON, CAMERA_MODE_FIRST_PERSON,
CAMERA_MODE_MY_OWN_FACE, CAMERA_MODE_MIRROR,
NUM_CAMERA_MODES NUM_CAMERA_MODES
}; };
@ -39,6 +39,7 @@ public:
void setTargetYaw ( float y ) { _idealYaw = y; } void setTargetYaw ( float y ) { _idealYaw = y; }
void setPosition ( glm::vec3 p ) { _position = p; } void setPosition ( glm::vec3 p ) { _position = p; }
void setTightness ( float t ) { _tightness = t; } void setTightness ( float t ) { _tightness = t; }
void setTargetRotation( float yaw, float pitch, float roll );
void setMode ( CameraMode m ); void setMode ( CameraMode m );
void setFieldOfView ( float f ); void setFieldOfView ( float f );
@ -78,6 +79,8 @@ private:
float _upShift; float _upShift;
float _rightShift; float _rightShift;
float _idealYaw; float _idealYaw;
float _idealPitch;
float _idealRoll;
float _distance; float _distance;
float _tightness; float _tightness;
Orientation _orientation; Orientation _orientation;

View file

@ -29,7 +29,7 @@ int serialBufferPos = 0;
const int ZERO_OFFSET = 2048; const int ZERO_OFFSET = 2048;
const short NO_READ_MAXIMUM_MSECS = 3000; const short NO_READ_MAXIMUM_MSECS = 3000;
const short SAMPLES_TO_DISCARD = 100; // Throw out the first few samples const short SAMPLES_TO_DISCARD = 100; // Throw out the first few samples
const int GRAVITY_SAMPLES = 200; // Use the first samples to compute gravity vector const int GRAVITY_SAMPLES = 60; // Use the first samples to compute gravity vector
const bool USING_INVENSENSE_MPU9150 = 1; const bool USING_INVENSENSE_MPU9150 = 1;
@ -131,42 +131,11 @@ void SerialInterface::initializePort(char* portname, int baud) {
#endif #endif
} }
// Reset Trailing averages to the current measurement
void SerialInterface::resetTrailingAverages() {
for (int i = 1; i < NUM_CHANNELS; i++) trailingAverage[i] = lastMeasured[i];
}
// Render the serial interface channel values onscreen as vertical lines // Render the serial interface channel values onscreen as vertical lines
void SerialInterface::renderLevels(int width, int height) { void SerialInterface::renderLevels(int width, int height) {
int i;
int disp_x = 10;
const int GAP = 16;
char val[40]; char val[40];
if (!USING_INVENSENSE_MPU9150) { if (USING_INVENSENSE_MPU9150) {
for(i = 0; i < NUM_CHANNELS; i++) { // For invensense gyros, render as horizontal bars
// Actual value
glLineWidth(2.0);
glColor4f(1, 1, 1, 1);
glBegin(GL_LINES);
glVertex2f(disp_x, height * 0.95);
glVertex2f(disp_x, height * (0.25 + 0.75f * getValue(i) / 4096));
glColor4f(1, 0, 0, 1);
glVertex2f(disp_x - 3, height * (0.25 + 0.75f * getValue(i) / 4096));
glVertex2f(disp_x, height * (0.25 + 0.75f * getValue(i) / 4096));
glEnd();
// Trailing Average value
glBegin(GL_LINES);
glColor4f(1, 1, 1, 1);
glVertex2f(disp_x, height * (0.25 + 0.75f * getTrailingValue(i) / 4096));
glVertex2f(disp_x + 4, height * (0.25 + 0.75f * getTrailingValue(i) / 4096));
glEnd();
sprintf(val, "%d", getValue(i));
drawtext(disp_x - GAP / 2, (height * 0.95) + 2, 0.08, 90, 1.0, 0, val, 0, 1, 0);
disp_x += GAP;
}
} else {
const int LEVEL_CORNER_X = 10; const int LEVEL_CORNER_X = 10;
const int LEVEL_CORNER_Y = 200; const int LEVEL_CORNER_Y = 200;
@ -177,18 +146,37 @@ void SerialInterface::renderLevels(int width, int height) {
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 15, 0.10, 0, 1.0, 1, val, 0, 1, 0); drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 15, 0.10, 0, 1.0, 1, val, 0, 1, 0);
sprintf(val, "Roll %4.1f", _lastRollRate); sprintf(val, "Roll %4.1f", _lastRollRate);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 30, 0.10, 0, 1.0, 1, val, 0, 1, 0); drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 30, 0.10, 0, 1.0, 1, val, 0, 1, 0);
sprintf(val, "X %4.3f", _lastAccelX);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 45, 0.10, 0, 1.0, 1, val, 0, 1, 0);
sprintf(val, "Y %4.3f", _lastAccelY);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 60, 0.10, 0, 1.0, 1, val, 0, 1, 0);
sprintf(val, "Z %4.3f", _lastAccelZ);
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 75, 0.10, 0, 1.0, 1, val, 0, 1, 0);
// Draw the levels as horizontal lines // Draw the levels as horizontal lines
const int LEVEL_CENTER = 150; const int LEVEL_CENTER = 150;
const float ACCEL_VIEW_SCALING = 50.f;
glLineWidth(2.0); glLineWidth(2.0);
glColor4f(1, 1, 1, 1); glColor4f(1, 1, 1, 1);
glBegin(GL_LINES); glBegin(GL_LINES);
// Gyro rates
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 3); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 3);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastYawRate, LEVEL_CORNER_Y - 3); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastYawRate, LEVEL_CORNER_Y - 3);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 12); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 12);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastPitchRate, LEVEL_CORNER_Y + 12); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastPitchRate, LEVEL_CORNER_Y + 12);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 27); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 27);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastRollRate, LEVEL_CORNER_Y + 27); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastRollRate, LEVEL_CORNER_Y + 27);
// Acceleration
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 42);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)((_lastAccelX - _gravity.x)* ACCEL_VIEW_SCALING),
LEVEL_CORNER_Y + 42);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 57);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)((_lastAccelY - _gravity.y) * ACCEL_VIEW_SCALING),
LEVEL_CORNER_Y + 57);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 72);
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)((_lastAccelZ - _gravity.z) * ACCEL_VIEW_SCALING),
LEVEL_CORNER_Y + 72);
glEnd(); glEnd();
// Draw green vertical centerline // Draw green vertical centerline
glColor4f(0, 1, 0, 0.5); glColor4f(0, 1, 0, 0.5);
@ -197,18 +185,6 @@ void SerialInterface::renderLevels(int width, int height) {
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 30); glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 30);
glEnd(); glEnd();
} }
// Display Serial latency block
if (LED) {
glColor3f(1,0,0);
glBegin(GL_QUADS); {
glVertex2f(width - 100, height - 100);
glVertex2f(width, height - 100);
glVertex2f(width, height);
glVertex2f(width - 100, height);
}
glEnd();
}
} }
void convertHexToInt(unsigned char* sourceBuffer, int& destinationInt) { void convertHexToInt(unsigned char* sourceBuffer, int& destinationInt) {
@ -237,15 +213,17 @@ void SerialInterface::readData() {
int accelXRate, accelYRate, accelZRate; int accelXRate, accelYRate, accelZRate;
convertHexToInt(sensorBuffer + 6, accelXRate); convertHexToInt(sensorBuffer + 6, accelZRate);
convertHexToInt(sensorBuffer + 10, accelYRate); convertHexToInt(sensorBuffer + 10, accelYRate);
convertHexToInt(sensorBuffer + 14, accelZRate); convertHexToInt(sensorBuffer + 14, accelXRate);
const float LSB_TO_METERS_PER_SECOND = 1.f / 16384.f; const float LSB_TO_METERS_PER_SECOND2 = 1.f / 16384.f * 9.80665f;
// From MPU-9150 register map, with setting on
// highest resolution = +/- 2G
_lastAccelX = ((float) accelXRate) * LSB_TO_METERS_PER_SECOND; _lastAccelX = ((float) accelXRate) * LSB_TO_METERS_PER_SECOND2;
_lastAccelY = ((float) accelYRate) * LSB_TO_METERS_PER_SECOND; _lastAccelY = ((float) accelYRate) * LSB_TO_METERS_PER_SECOND2;
_lastAccelZ = ((float) accelZRate) * LSB_TO_METERS_PER_SECOND; _lastAccelZ = ((float) -accelZRate) * LSB_TO_METERS_PER_SECOND2;
int rollRate, yawRate, pitchRate; int rollRate, yawRate, pitchRate;
@ -262,61 +240,20 @@ void SerialInterface::readData() {
_lastYawRate = ((float) yawRate) * LSB_TO_DEGREES_PER_SECOND; _lastYawRate = ((float) yawRate) * LSB_TO_DEGREES_PER_SECOND;
_lastPitchRate = ((float) -pitchRate) * LSB_TO_DEGREES_PER_SECOND + PITCH_BIAS; _lastPitchRate = ((float) -pitchRate) * LSB_TO_DEGREES_PER_SECOND + PITCH_BIAS;
totalSamples++; // Accumulate an initial reading for gravity
} else { // Use a set of initial samples to compute gravity
// This array sets the rate of trailing averaging for each channel: if (totalSamples < GRAVITY_SAMPLES) {
// If the sensor rate is 100Hz, 0.001 will make the long term average a 10-second average _gravity.x += _lastAccelX;
const float AVG_RATE[] = {0.002, 0.002, 0.002, 0.002, 0.002, 0.002}; _gravity.y += _lastAccelY;
char bufchar[1]; _gravity.z += _lastAccelZ;
while (read(_serialDescriptor, &bufchar, 1) > 0) {
serialBuffer[serialBufferPos] = bufchar[0];
serialBufferPos++;
// Have we reached end of a line of input?
if ((bufchar[0] == '\n') || (serialBufferPos >= MAX_BUFFER)) {
std::string serialLine(serialBuffer, serialBufferPos-1);
//printLog("%s\n", serialLine.c_str());
int spot;
//int channel = 0;
std::string val;
for (int i = 0; i < NUM_CHANNELS + 2; i++) {
spot = serialLine.find_first_of(" ", 0);
if (spot != std::string::npos) {
val = serialLine.substr(0,spot);
//printLog("%s\n", val.c_str());
if (i < NUM_CHANNELS) lastMeasured[i] = atoi(val.c_str());
else samplesAveraged = atoi(val.c_str());
} else LED = atoi(serialLine.c_str());
serialLine = serialLine.substr(spot+1, serialLine.length() - spot - 1);
}
// Update Trailing Averages
for (int i = 0; i < NUM_CHANNELS; i++) {
if (totalSamples > SAMPLES_TO_DISCARD) {
trailingAverage[i] = (1.f - AVG_RATE[i])*trailingAverage[i] +
AVG_RATE[i]*(float)lastMeasured[i];
} else {
trailingAverage[i] = (float)lastMeasured[i];
}
}
// Use a set of initial samples to compute gravity
if (totalSamples < GRAVITY_SAMPLES) {
gravity.x += lastMeasured[ACCEL_X];
gravity.y += lastMeasured[ACCEL_Y];
gravity.z += lastMeasured[ACCEL_Z];
}
if (totalSamples == GRAVITY_SAMPLES) {
gravity = glm::normalize(gravity);
printLog("gravity: %f,%f,%f\n", gravity.x, gravity.y, gravity.z);
}
totalSamples++;
serialBufferPos = 0;
}
} }
} if (totalSamples == GRAVITY_SAMPLES) {
_gravity /= (float) totalSamples;
printLog("Gravity: %f\n", glm::length(_gravity));
}
totalSamples++;
}
if (initialSamples == totalSamples) { if (initialSamples == totalSamples) {
timeval now; timeval now;
@ -336,23 +273,10 @@ void SerialInterface::resetSerial() {
#ifdef __APPLE__ #ifdef __APPLE__
active = false; active = false;
totalSamples = 0; totalSamples = 0;
_gravity = glm::vec3(0, 0, 0);
gettimeofday(&lastGoodRead, NULL); gettimeofday(&lastGoodRead, NULL);
if (!USING_INVENSENSE_MPU9150) {
gravity = glm::vec3(0, -1, 0);
// Clear the measured and average channel data
for (int i = 0; i < NUM_CHANNELS; i++) {
lastMeasured[i] = 0;
trailingAverage[i] = 0.0;
}
// Clear serial input buffer
for (int i = 1; i < MAX_BUFFER; i++) {
serialBuffer[i] = ' ';
}
}
#endif #endif
} }

View file

@ -32,7 +32,7 @@
#define HEAD_YAW_RATE 0 #define HEAD_YAW_RATE 0
#define HEAD_ROLL_RATE 2 #define HEAD_ROLL_RATE 2
extern const bool USING_INVENSENSE_MPU9150; //const bool USING_INVENSENSE_MPU9150;
class SerialInterface { class SerialInterface {
public: public:
@ -50,30 +50,20 @@ public:
float getLastYawRate() const { return _lastYawRate; } float getLastYawRate() const { return _lastYawRate; }
float getLastPitchRate() const { return _lastPitchRate; } float getLastPitchRate() const { return _lastPitchRate; }
float getLastRollRate() const { return _lastRollRate; } float getLastRollRate() const { return _lastRollRate; }
glm::vec3 getLastAcceleration() { return glm::vec3(_lastAccelX, _lastAccelY, _lastAccelZ); };
glm::vec3 getGravity() {return _gravity;};
int getLED() {return LED;};
int getNumSamples() {return samplesAveraged;};
int getValue(int num) {return lastMeasured[num];};
int getRelativeValue(int num) {return static_cast<int>(lastMeasured[num] - trailingAverage[num]);};
float getTrailingValue(int num) {return trailingAverage[num];};
void resetTrailingAverages();
void renderLevels(int width, int height); void renderLevels(int width, int height);
bool active; bool active;
glm::vec3 getGravity() {return gravity;};
private: private:
void initializePort(char* portname, int baud); void initializePort(char* portname, int baud);
void resetSerial(); void resetSerial();
int _serialDescriptor; int _serialDescriptor;
int lastMeasured[NUM_CHANNELS];
float trailingAverage[NUM_CHANNELS];
int samplesAveraged;
int LED;
int totalSamples; int totalSamples;
timeval lastGoodRead; timeval lastGoodRead;
glm::vec3 gravity; glm::vec3 _gravity;
float _lastAccelX; float _lastAccelX;
float _lastAccelY; float _lastAccelY;
float _lastAccelZ; float _lastAccelZ;

View file

@ -67,8 +67,8 @@ float angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float
} }
// Helper function returns the positive angle in degrees between two 3D vectors // Helper function returns the positive angle in degrees between two 3D vectors
float angleBetween(glm::vec3 * v1, glm::vec3 * v2) { float angleBetween(const glm::vec3& v1, const glm::vec3& v2) {
return acos((glm::dot(*v1, *v2)) / (glm::length(*v1) * glm::length(*v2))) * 180.f / PI; return acos((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2))) * 180.f / PI;
} }
// Draw a 3D vector floating in space // Draw a 3D vector floating in space

View file

@ -44,7 +44,7 @@ void noiseTest(int w, int h);
void drawVector(glm::vec3* vector); void drawVector(glm::vec3* vector);
float angleBetween(glm::vec3 * v1, glm::vec3 * v2); float angleBetween(const glm::vec3& v1, const glm::vec3& v2);
double diffclock(timeval *clock1,timeval *clock2); double diffclock(timeval *clock1,timeval *clock2);

View file

@ -43,7 +43,7 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- .
VoxelSystem::VoxelSystem() { VoxelSystem::VoxelSystem() {
_voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0;
_alwaysRenderFullVBO = true; _renderFullVBO = true;
_tree = new VoxelTree(); _tree = new VoxelTree();
pthread_mutex_init(&_bufferWriteLock, NULL); pthread_mutex_init(&_bufferWriteLock, NULL);
} }
@ -138,8 +138,9 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
PerformanceWarning warn(_renderWarningsOn, "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated PerformanceWarning warn(_renderWarningsOn, "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated
double start = usecTimestampNow(); double start = usecTimestampNow();
double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0; double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0;
if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging
if (!iAmDebugging && sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) {
return; // bail early, it hasn't been long enough since the last time we ran return; // bail early, it hasn't been long enough since the last time we ran
} }
@ -147,19 +148,37 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
// If the view frustum has changed, since last time, then remove nodes that are out of view // If the view frustum has changed, since last time, then remove nodes that are out of view
if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) && hasViewChanged()) { if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) && hasViewChanged()) {
_lastViewCulling = start; _lastViewCulling = start;
// When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove
// them from tree, this makes our tree caclulations faster, but doesn't require us to fully rebuild the VBOs (which
// can be expensive).
removeOutOfView(); removeOutOfView();
// Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So,
// we should consider putting this someplace else... as this might be able to occur less frequently, and save us on
// VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary.
cleanupRemovedVoxels();
double endViewCulling = usecTimestampNow(); double endViewCulling = usecTimestampNow();
_lastViewCullingElapsed = (endViewCulling - start) / 1000.0; _lastViewCullingElapsed = (endViewCulling - start) / 1000.0;
} }
if (_tree->isDirty()) { if (_tree->isDirty()) {
PerformanceWarning warn(_renderWarningsOn, "calling... newTreeToArrays()"); static char buffer[64] = { 0 };
if (_renderWarningsOn) {
sprintf(buffer, "newTreeToArrays() _renderFullVBO=%s", (_renderFullVBO ? "yes" : "no"));
};
PerformanceWarning warn(_renderWarningsOn, buffer);
_callsToTreesToArrays++; _callsToTreesToArrays++;
if (_alwaysRenderFullVBO) { if (_renderFullVBO) {
_voxelsInWriteArrays = 0; // reset our VBO _voxelsInWriteArrays = 0; // reset our VBO
} }
_voxelsUpdated = newTreeToArrays(_tree->rootNode); _voxelsUpdated = newTreeToArrays(_tree->rootNode);
_tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean
// since we called treeToArrays, we can assume that our VBO is in sync, and so partial updates to the VBOs are
// ok again, until/unless we call removeOutOfView()
_renderFullVBO = false;
} else { } else {
_voxelsUpdated = 0; _voxelsUpdated = 0;
} }
@ -176,6 +195,16 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
_setupNewVoxelsForDrawingLastElapsed = elapsedmsec; _setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
} }
void VoxelSystem::cleanupRemovedVoxels() {
PerformanceWarning warn(_renderWarningsOn, "cleanupRemovedVoxels()");
if (!_removedVoxels.isEmpty()) {
while (!_removedVoxels.isEmpty()) {
delete _removedVoxels.extract();
}
_renderFullVBO = true; // if we remove voxels, we must update our full VBOs
}
}
void VoxelSystem::copyWrittenDataToReadArrays() { void VoxelSystem::copyWrittenDataToReadArrays() {
PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated
if (_voxelsDirty && _voxelsUpdated) { if (_voxelsDirty && _voxelsUpdated) {
@ -210,16 +239,16 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) {
voxelsUpdated += newTreeToArrays(node->getChildAtIndex(i)); voxelsUpdated += newTreeToArrays(node->getChildAtIndex(i));
} }
} }
if (_alwaysRenderFullVBO) { if (_renderFullVBO) {
voxelsUpdated += newway__updateNodeInArray(node); voxelsUpdated += updateNodeInArraysAsFullVBO(node);
} else { } else {
voxelsUpdated += oldway__updateNodeInArray(node); voxelsUpdated += updateNodeInArraysAsPartialVBO(node);
} }
node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered
return voxelsUpdated; return voxelsUpdated;
} }
int VoxelSystem::newway__updateNodeInArray(VoxelNode* node) { int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) {
// If we've run out of room, then just bail... // If we've run out of room, then just bail...
if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) { if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) {
return 0; return 0;
@ -238,18 +267,24 @@ int VoxelSystem::newway__updateNodeInArray(VoxelNode* node) {
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
*(writeColorsAt +j) = node->getColor()[j % 3]; *(writeColorsAt +j) = node->getColor()[j % 3];
} }
_voxelsInWriteArrays++; // our know vertices in the arrays node->setBufferIndex(nodeIndex);
_voxelDirtyArray[nodeIndex] = true; // just in case we switch to Partial mode
_voxelsInWriteArrays++; // our know vertices in the arrays
return 1; // rendered return 1; // rendered
} }
return 0; // not-rendered return 0; // not-rendered
} }
int VoxelSystem::oldway__updateNodeInArray(VoxelNode* node) { int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) {
// Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us // If we've run out of room, then just bail...
if (node->isDirty() && (node->getShouldRender() || node->isKnownBufferIndex())) { if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) {
return 0;
}
// Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays...
if (node->isDirty()) {
glm::vec3 startVertex; glm::vec3 startVertex;
float voxelScale = 0; float voxelScale = 0;
// If we're should render, use our legit location and scale, // If we're should render, use our legit location and scale,
if (node->getShouldRender()) { if (node->getShouldRender()) {
startVertex = node->getCorner(); startVertex = node->getCorner();
@ -267,8 +302,9 @@ int VoxelSystem::oldway__updateNodeInArray(VoxelNode* node) {
nodeIndex = node->getBufferIndex(); nodeIndex = node->getBufferIndex();
} else { } else {
nodeIndex = _voxelsInWriteArrays; nodeIndex = _voxelsInWriteArrays;
node->setBufferIndex(nodeIndex);
_voxelsInWriteArrays++;
} }
_voxelDirtyArray[nodeIndex] = true; _voxelDirtyArray[nodeIndex] = true;
// populate the array with points for the 8 vertices // populate the array with points for the 8 vertices
@ -279,10 +315,6 @@ int VoxelSystem::oldway__updateNodeInArray(VoxelNode* node) {
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
*(writeColorsAt +j) = node->getColor()[j % 3]; *(writeColorsAt +j) = node->getColor()[j % 3];
} }
if (!node->isKnownBufferIndex()) {
node->setBufferIndex(nodeIndex);
_voxelsInWriteArrays++; // our know vertices in the arrays
}
return 1; // updated! return 1; // updated!
} }
return 0; // not-updated return 0; // not-updated
@ -373,53 +405,90 @@ void VoxelSystem::init() {
delete[] normalsArray; delete[] normalsArray;
} }
void VoxelSystem::updateVBOs() { void VoxelSystem::updateFullVBOs() {
PerformanceWarning warn(_renderWarningsOn, "updateVBOs()"); // would like to include _callsToTreesToArrays glBufferIndex segmentStart = 0;
if (_voxelsDirty) { glBufferIndex segmentEnd = _voxelsInWriteArrays;
if (_alwaysRenderFullVBO) {
glBufferIndex segmentStart = 0; int segmentLength = (segmentEnd - segmentStart) + 1;
glBufferIndex segmentEnd = _voxelsInWriteArrays; GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
int segmentLength = (segmentEnd - segmentStart) + 1; GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); // consider the _voxelDirtyArray[] clean!
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); memset(_voxelDirtyArray, false, _voxelsInWriteArrays * sizeof(bool));
} else { }
glBufferIndex segmentStart = 0;
glBufferIndex segmentEnd = 0; void VoxelSystem::updatePartialVBOs() {
bool inSegment = false; glBufferIndex segmentStart = 0;
for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { glBufferIndex segmentEnd = 0;
if (!inSegment) { bool inSegment = false;
if (_voxelDirtyArray[i]) { for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) {
segmentStart = i; bool thisVoxelDirty = _voxelDirtyArray[i];
inSegment = true; if (!inSegment) {
_voxelDirtyArray[i] = false; // consider us clean! if (thisVoxelDirty) {
} segmentStart = i;
} else { inSegment = true;
if (!_voxelDirtyArray[i] || (i == (_voxelsInWriteArrays - 1)) ) { _voxelDirtyArray[i] = false; // consider us clean!
segmentEnd = i;
inSegment = false;
int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
}
}
} }
} else {
if (!thisVoxelDirty) {
// If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before
// this one and so that's where the "segment" ends
segmentEnd = i - 1;
inSegment = false;
int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
}
_voxelDirtyArray[i] = false; // consider us clean!
}
}
// if we got to the end of the array, and we're in an active dirty segment...
if (inSegment) {
segmentEnd = _voxelsInWriteArrays - 1;
inSegment = false;
int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
}
}
void VoxelSystem::updateVBOs() {
static char buffer[40] = { 0 };
if (_renderWarningsOn) {
sprintf(buffer, "updateVBOs() _renderFullVBO=%s", (_renderFullVBO ? "yes" : "no"));
};
PerformanceWarning warn(_renderWarningsOn, buffer); // would like to include _callsToTreesToArrays
if (_voxelsDirty) {
// updatePartialVBOs() is not yet working. For now, ALWAYS call updateFullVBOs()
if (_renderFullVBO) {
updateFullVBOs();
} else {
updatePartialVBOs(); // too many small segments?
} }
_voxelsDirty = false; _voxelsDirty = false;
} }
@ -672,10 +741,14 @@ void VoxelSystem::removeOutOfView() {
removeOutOfViewArgs args(this); removeOutOfViewArgs args(this);
_tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)&args); _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)&args);
if (_renderWarningsOn) { if (args.nodesRemoved) {
printLog("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld bag.count()=%d \n", _tree->setDirtyBit();
}
bool showRemoveDebugDetails = false;
if (showRemoveDebugDetails) {
printLog("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d \n",
args.nodesScanned, args.nodesRemoved, args.nodesInside, args.nodesScanned, args.nodesRemoved, args.nodesInside,
args.nodesIntersect, args.nodesOutside, args.dontRecurseBag.count() args.nodesIntersect, args.nodesOutside, _removedVoxels.count()
); );
} }
} }
@ -695,3 +768,160 @@ bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3&
detail.blue = node->getColor()[2]; detail.blue = node->getColor()[2];
return true; return true;
} }
class falseColorizeRandomEveryOtherArgs {
public:
falseColorizeRandomEveryOtherArgs() : totalNodes(0), colorableNodes(0), coloredNodes(0), colorThis(true) {};
unsigned long totalNodes;
unsigned long colorableNodes;
unsigned long coloredNodes;
bool colorThis;
};
bool VoxelSystem::falseColorizeRandomEveryOtherOperation(VoxelNode* node, void* extraData) {
falseColorizeRandomEveryOtherArgs* args = (falseColorizeRandomEveryOtherArgs*)extraData;
args->totalNodes++;
if (node->isColored()) {
args->colorableNodes++;
if (args->colorThis) {
args->coloredNodes++;
node->setFalseColor(255, randomColorValue(150), randomColorValue(150));
}
args->colorThis = !args->colorThis;
}
return true; // keep going!
}
void VoxelSystem::falseColorizeRandomEveryOther() {
falseColorizeRandomEveryOtherArgs args;
_tree->recurseTreeWithOperation(falseColorizeRandomEveryOtherOperation,&args);
printLog("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n",
args.totalNodes, args.colorableNodes, args.coloredNodes);
setupNewVoxelsForDrawing();
}
class collectStatsForTreesAndVBOsArgs {
public:
collectStatsForTreesAndVBOsArgs() :
totalNodes(0),
dirtyNodes(0),
shouldRenderNodes(0),
coloredNodes(0),
nodesInVBO(0),
nodesInVBOOverExpectedMax(0),
duplicateVBOIndex(0)
{
memset(hasIndexFound, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool));
};
unsigned long totalNodes;
unsigned long dirtyNodes;
unsigned long shouldRenderNodes;
unsigned long coloredNodes;
unsigned long nodesInVBO;
unsigned long nodesInVBOOverExpectedMax;
unsigned long duplicateVBOIndex;
unsigned long expectedMax;
bool colorThis;
bool hasIndexFound[MAX_VOXELS_PER_SYSTEM];
};
bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData) {
collectStatsForTreesAndVBOsArgs* args = (collectStatsForTreesAndVBOsArgs*)extraData;
args->totalNodes++;
if (node->isColored()) {
args->coloredNodes++;
}
if (node->getShouldRender()) {
args->shouldRenderNodes++;
}
if (node->isDirty()) {
args->dirtyNodes++;
}
if (node->isKnownBufferIndex()) {
args->nodesInVBO++;
unsigned long nodeIndex = node->getBufferIndex();
if (args->hasIndexFound[nodeIndex]) {
args->duplicateVBOIndex++;
printLog("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex,
node->isDirty() ? "yes" : "no" , node->getShouldRender() ? "yes" : "no" );
} else {
args->hasIndexFound[nodeIndex] = true;
}
if (nodeIndex > args->expectedMax) {
args->nodesInVBOOverExpectedMax++;
}
}
return true; // keep going!
}
void VoxelSystem::collectStatsForTreesAndVBOs() {
glBufferIndex minDirty = GLBUFFER_INDEX_UNKNOWN;
glBufferIndex maxDirty = 0;
for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) {
if (_voxelDirtyArray[i]) {
minDirty = std::min(minDirty,i);
maxDirty = std::max(maxDirty,i);
}
}
collectStatsForTreesAndVBOsArgs args;
args.expectedMax = _voxelsInWriteArrays;
_tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args);
printLog("_voxelsDirty=%s _voxelsInWriteArrays=%ld minDirty=%ld maxDirty=%ld \n", (_voxelsDirty ? "yes" : "no"),
_voxelsInWriteArrays, minDirty, maxDirty);
printLog("stats: total %ld, dirty %ld, colored %ld, shouldRender %ld, inVBO %ld, nodesInVBOOverExpectedMax %ld, duplicateVBOIndex %ld\n",
args.totalNodes, args.dirtyNodes, args.coloredNodes, args.shouldRenderNodes,
args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex);
glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN;
glBufferIndex maxInVBO = 0;
for (glBufferIndex i = 0; i < MAX_VOXELS_PER_SYSTEM; i++) {
if (args.hasIndexFound[i]) {
minInVBO = std::min(minInVBO,i);
maxInVBO = std::max(maxInVBO,i);
}
}
printLog("minInVBO=%ld maxInVBO=%ld _voxelsInWriteArrays=%ld _voxelsInReadArrays=%ld\n",
minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays);
}
void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) {
//printLog("VoxelSystem::deleteVoxelAt(%f,%f,%f,%f)\n",x,y,z,s);
_tree->deleteVoxelAt(x, y, z, s);
setupNewVoxelsForDrawing();
};
VoxelNode* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const {
return _tree->getVoxelAt(x, y, z, s);
};
void VoxelSystem::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue) {
//printLog("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s);
_tree->createVoxel(x, y, z, s, red, green, blue);
setupNewVoxelsForDrawing();
};
void VoxelSystem::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color) {
_tree->createLine(point1, point2, unitSize, color);
setupNewVoxelsForDrawing();
};
void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool debug) {
_tree->createSphere(r, xc, yc, zc, s, solid, mode, debug);
setupNewVoxelsForDrawing();
};

View file

@ -57,6 +57,7 @@ public:
void trueColorize(); void trueColorize();
void falseColorizeInView(ViewFrustum* viewFrustum); void falseColorizeInView(ViewFrustum* viewFrustum);
void falseColorizeDistanceFromView(ViewFrustum* viewFrustum); void falseColorizeDistanceFromView(ViewFrustum* viewFrustum);
void falseColorizeRandomEveryOther();
void killLocalVoxels(); void killLocalVoxels();
void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; }; void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; };
@ -67,6 +68,14 @@ public:
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
VoxelDetail& detail, float& distance, BoxFace& face); VoxelDetail& detail, float& distance, BoxFace& face);
void collectStatsForTreesAndVBOs();
void deleteVoxelAt(float x, float y, float z, float s);
VoxelNode* getVoxelAt(float x, float y, float z, float s) const;
void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue);
void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color);
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool debug = false);
private: private:
int _callsToTreesToArrays; int _callsToTreesToArrays;
@ -82,9 +91,11 @@ private:
static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData); static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData);
static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData); static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData);
static bool removeOutOfViewOperation(VoxelNode* node, void* extraData); static bool removeOutOfViewOperation(VoxelNode* node, void* extraData);
static bool falseColorizeRandomEveryOtherOperation(VoxelNode* node, void* extraData);
static bool collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData);
int newway__updateNodeInArray(VoxelNode* node); int updateNodeInArraysAsFullVBO(VoxelNode* node);
int oldway__updateNodeInArray(VoxelNode* node); int updateNodeInArraysAsPartialVBO(VoxelNode* node);
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
static float _maxDistance; static float _maxDistance;
@ -103,7 +114,7 @@ private:
unsigned long _voxelsInReadArrays; unsigned long _voxelsInReadArrays;
unsigned long _unusedArraySpace; unsigned long _unusedArraySpace;
bool _alwaysRenderFullVBO; bool _renderFullVBO;
double _setupNewVoxelsForDrawingLastElapsed; double _setupNewVoxelsForDrawingLastElapsed;
double _setupNewVoxelsForDrawingLastFinished; double _setupNewVoxelsForDrawingLastFinished;
@ -120,11 +131,18 @@ private:
ViewFrustum _lastKnowViewFrustum; ViewFrustum _lastKnowViewFrustum;
int newTreeToArrays(VoxelNode *currentNode); int newTreeToArrays(VoxelNode *currentNode);
void cleanupRemovedVoxels();
void setupNewVoxelsForDrawing(); void setupNewVoxelsForDrawing();
void copyWrittenDataToReadArrays(); void copyWrittenDataToReadArrays();
void updateVBOs();
bool _voxelsDirty; bool _voxelsDirty;
public:
void updateVBOs();
void updateFullVBOs(); // all voxels in the VBO
void updatePartialVBOs(); // multiple segments, only dirty voxels
}; };
#endif #endif

View file

@ -98,12 +98,13 @@ int packetsPerSecond = 0;
int bytesPerSecond = 0; int bytesPerSecond = 0;
int bytesCount = 0; int bytesCount = 0;
int WIDTH = 1200; // Window size int WIDTH = 1200; // Window size
int HEIGHT = 800; int HEIGHT = 800;
int fullscreen = 0; int fullscreen = 0;
float aspectRatio = 1.0f; float aspectRatio = 1.0f;
bool USING_FIRST_PERSON_EFFECT = false; //CameraMode defaultCameraMode = CAMERA_MODE_FIRST_PERSON;
CameraMode defaultCameraMode = CAMERA_MODE_THIRD_PERSON;
bool wantColorRandomizer = true; // for addSphere and load file bool wantColorRandomizer = true; // for addSphere and load file
@ -112,7 +113,7 @@ Oscilloscope audioScope(256,200,true);
ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc. ViewFrustum viewFrustum; // current state of view frustum, perspective, orientation, etc.
Avatar 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 myCamera; // My view onto the world
Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode Camera viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
AvatarRenderer avatarRenderer; AvatarRenderer avatarRenderer;
@ -325,8 +326,10 @@ void init(void) {
if (noiseOn) { if (noiseOn) {
myAvatar.setNoise(noise); myAvatar.setNoise(noise);
} }
myAvatar.setPosition(start_location); myAvatar.setPosition(start_location);
myCamera.setPosition(start_location); myCamera.setPosition(start_location);
myCamera.setMode(defaultCameraMode);
#ifdef MARKER_CAPTURE #ifdef MARKER_CAPTURE
@ -370,10 +373,6 @@ void reset_sensors() {
headMouseY = HEIGHT/2; headMouseY = HEIGHT/2;
myAvatar.reset(); myAvatar.reset();
if (serialPort.active) {
serialPort.resetTrailingAverages();
}
} }
void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) {
@ -395,15 +394,9 @@ void updateAvatar(float deltaTime) {
myAvatar.updateHeadFromGyros(deltaTime, &serialPort, &gravity); myAvatar.updateHeadFromGyros(deltaTime, &serialPort, &gravity);
// Grab latest readings from the gyros // Grab latest readings from the gyros
float measuredYawRate, measuredPitchRate; float measuredPitchRate = serialPort.getLastPitchRate();
if (USING_INVENSENSE_MPU9150) { float measuredYawRate = serialPort.getLastYawRate();
measuredPitchRate = serialPort.getLastPitchRate();
measuredYawRate = serialPort.getLastYawRate();
} else {
measuredPitchRate = serialPort.getRelativeValue(HEAD_PITCH_RATE);
measuredYawRate = serialPort.getRelativeValue(HEAD_YAW_RATE);
}
// Update gyro-based mouse (X,Y on screen) // Update gyro-based mouse (X,Y on screen)
const float MIN_MOUSE_RATE = 30.0; const float MIN_MOUSE_RATE = 30.0;
const float MOUSE_SENSITIVITY = 0.1f; const float MOUSE_SENSITIVITY = 0.1f;
@ -1031,90 +1024,32 @@ void display(void)
glLoadIdentity(); glLoadIdentity();
// camera settings // camera settings
if (::lookingInMirror) { if (myCamera.getMode() == CAMERA_MODE_MIRROR) {
// set the camera to looking at my own face myAvatar.setDisplayingHead(true);
myCamera.setTargetPosition (myAvatar.getHeadPosition()); myCamera.setUpShift (0.0);
myCamera.setTargetYaw (myAvatar.getBodyYaw() - 180.0f); // 180 degrees from body yaw myCamera.setDistance (0.2);
myCamera.setPitch (0.0); myCamera.setTightness (100.0f);
myCamera.setRoll (0.0);
myCamera.setUpShift (0.0);
myCamera.setDistance (0.2);
myCamera.setTightness (100.0f);
} else {
//float firstPersonPitch = 20.0f;
//float firstPersonUpShift = 0.0f;
//float firstPersonDistance = 0.0f;
//float firstPersonTightness = 100.0f;
float firstPersonPitch = 20.0f + myAvatar.getRenderPitch();
float firstPersonUpShift = 0.1f;
float firstPersonDistance = 0.4f;
float firstPersonTightness = 100.0f;
float thirdPersonPitch = 0.0f + myAvatar.getRenderPitch();
float thirdPersonUpShift = -0.2f;
float thirdPersonDistance = 1.2f;
float thirdPersonTightness = 8.0f;
if (USING_FIRST_PERSON_EFFECT) {
float ff = 0.0;
float min = 0.1;
float max = 0.5;
if (myAvatar.getIsNearInteractingOther()){
if (myAvatar.getSpeed() < max) {
float s = (myAvatar.getSpeed()- min)/max ;
ff = 1.0 - s;
}
}
myCamera.setPitch (thirdPersonPitch + ff * (firstPersonPitch - thirdPersonPitch ));
myCamera.setUpShift (thirdPersonUpShift + ff * (firstPersonUpShift - thirdPersonUpShift ));
myCamera.setDistance (thirdPersonDistance + ff * (firstPersonDistance - thirdPersonDistance ));
myCamera.setTightness (thirdPersonTightness + ff * (firstPersonTightness - thirdPersonTightness));
// this version uses a ramp-up/ramp-down timer in the camera to determine shift between first and thirs-person view
/*
if (myAvatar.getSpeed() < 0.02) {
if (myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) {
myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
}
//printf("myCamera.getModeShift() = %f\n", myCamera.getModeShift());
myCamera.setPitch (thirdPersonPitch + myCamera.getModeShift() * (firstPersonPitch - thirdPersonPitch ));
myCamera.setUpShift (thirdPersonUpShift + myCamera.getModeShift() * (firstPersonUpShift - thirdPersonUpShift ));
myCamera.setDistance (thirdPersonDistance + myCamera.getModeShift() * (firstPersonDistance - thirdPersonDistance ));
myCamera.setTightness (thirdPersonTightness + myCamera.getModeShift() * (firstPersonTightness - thirdPersonTightness));
} else {
if (myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) {
myCamera.setMode(CAMERA_MODE_THIRD_PERSON);
}
//printf("myCamera.getModeShift() = %f\n", myCamera.getModeShift());
myCamera.setPitch (firstPersonPitch + myCamera.getModeShift() * (thirdPersonPitch - firstPersonPitch ));
myCamera.setUpShift (firstPersonUpShift + myCamera.getModeShift() * (thirdPersonUpShift - firstPersonUpShift ));
myCamera.setDistance (firstPersonDistance + myCamera.getModeShift() * (thirdPersonDistance - firstPersonDistance ));
myCamera.setTightness (firstPersonTightness + myCamera.getModeShift() * (thirdPersonTightness - firstPersonTightness));
}
*/
} else {
myCamera.setPitch (thirdPersonPitch );
myCamera.setUpShift (thirdPersonUpShift );
myCamera.setDistance (thirdPersonDistance );
myCamera.setTightness(thirdPersonTightness);
}
myCamera.setTargetPosition(myAvatar.getHeadPosition()); myCamera.setTargetPosition(myAvatar.getHeadPosition());
myCamera.setTargetYaw (myAvatar.getBodyYaw()); myCamera.setTargetRotation(myAvatar.getBodyYaw() - 180.0f, 0.0f, 0.0f);
myCamera.setRoll (0.0);
} else if (myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
myAvatar.setDisplayingHead(false);
myCamera.setUpShift (0.0f);
myCamera.setDistance (0.0f);
myCamera.setTightness (100.0f);
myCamera.setTargetPosition(myAvatar.getHeadPosition());
myCamera.setTargetRotation(myAvatar.getAbsoluteHeadYaw(), myAvatar.getAbsoluteHeadPitch(), 0.0f);
} else if (myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
myAvatar.setDisplayingHead(true);
myCamera.setUpShift (-0.2f);
myCamera.setDistance (1.5f);
myCamera.setTightness (8.0f);
myCamera.setTargetPosition(myAvatar.getHeadPosition());
myCamera.setTargetRotation(myAvatar.getBodyYaw(), 0.0f, 0.0f);
} }
// important... // important...
myCamera.update( 1.f/FPS ); myCamera.update( 1.f/FPS );
// Render anything (like HUD items) that we want to be in 3D but not in worldspace // Render anything (like HUD items) that we want to be in 3D but not in worldspace
@ -1354,6 +1289,20 @@ int doRandomizeVoxelColors(int state) {
return state; return state;
} }
int doFalseRandomizeEveryOtherVoxelColors(int state) {
if (state == MENU_ROW_PICKED) {
::voxels.falseColorizeRandomEveryOther();
}
return state;
}
int doTreeStats(int state) {
if (state == MENU_ROW_PICKED) {
::voxels.collectStatsForTreesAndVBOs();
}
return state;
}
int doFalseRandomizeVoxelColors(int state) { int doFalseRandomizeVoxelColors(int state) {
if (state == MENU_ROW_PICKED) { if (state == MENU_ROW_PICKED) {
::voxels.falseColorizeRandom(); ::voxels.falseColorizeRandom();
@ -1450,9 +1399,11 @@ void initMenu() {
menuColumnDebug->addRow("Kill Local Voxels", doKillLocalVoxels); menuColumnDebug->addRow("Kill Local Voxels", doKillLocalVoxels);
menuColumnDebug->addRow("Randomize Voxel TRUE Colors", doRandomizeVoxelColors); menuColumnDebug->addRow("Randomize Voxel TRUE Colors", doRandomizeVoxelColors);
menuColumnDebug->addRow("FALSE Color Voxels Randomly", doFalseRandomizeVoxelColors); menuColumnDebug->addRow("FALSE Color Voxels Randomly", doFalseRandomizeVoxelColors);
menuColumnDebug->addRow("FALSE Color Voxel Every Other Randomly", doFalseRandomizeEveryOtherVoxelColors);
menuColumnDebug->addRow("FALSE Color Voxels by Distance", doFalseColorizeByDistance); menuColumnDebug->addRow("FALSE Color Voxels by Distance", doFalseColorizeByDistance);
menuColumnDebug->addRow("FALSE Color Voxel Out of View", doFalseColorizeInView); menuColumnDebug->addRow("FALSE Color Voxel Out of View", doFalseColorizeInView);
menuColumnDebug->addRow("Show TRUE Colors", doTrueVoxelColors); menuColumnDebug->addRow("Show TRUE Colors", doTrueVoxelColors);
menuColumnDebug->addRow("Calculate Tree Stats", doTreeStats);
} }
void testPointToVoxel() { void testPointToVoxel() {
@ -1521,17 +1472,27 @@ void addVoxelInFrontOfAvatar() {
detail.blue = 128; detail.blue = 128;
sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, detail); sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, detail);
// create the voxel locally so it appears immediately
voxels.createVoxel(detail.x, detail.y, detail.z, detail.s, detail.red, detail.green, detail.blue);
} }
void addVoxelUnderCursor() { void addVoxelUnderCursor() {
if (::mouseVoxel.s != 0) { if (::mouseVoxel.s != 0) {
sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, ::mouseVoxel); sendVoxelEditMessage(PACKET_HEADER_SET_VOXEL, ::mouseVoxel);
// create the voxel locally so it appears immediately
voxels.createVoxel(::mouseVoxel.x, ::mouseVoxel.y, ::mouseVoxel.z, ::mouseVoxel.s,
::mouseVoxel.red, ::mouseVoxel.green, ::mouseVoxel.blue);
} }
} }
void deleteVoxelUnderCursor() { void deleteVoxelUnderCursor() {
if (::mouseVoxel.s != 0) { if (::mouseVoxel.s != 0) {
sendVoxelEditMessage(PACKET_HEADER_ERASE_VOXEL, ::mouseVoxel); sendVoxelEditMessage(PACKET_HEADER_ERASE_VOXEL, ::mouseVoxel);
// delete the voxel locally so it disappears immediately
voxels.deleteVoxelAt(::mouseVoxel.x, ::mouseVoxel.y, ::mouseVoxel.z, ::mouseVoxel.s);
} }
} }
@ -1618,7 +1579,12 @@ void key(unsigned char k, int x, int y) {
} }
// Process keypresses // Process keypresses
if (k == 'q' || k == 'Q') ::terminate();
if (k == 'S') {
::voxels.collectStatsForTreesAndVBOs();
}
if (k == 'q' || k == 'Q') ::terminate();
if (k == '/') ::renderStatsOn = !::renderStatsOn; // toggle stats if (k == '/') ::renderStatsOn = !::renderStatsOn; // toggle stats
if (k == '*') ::renderStarsOn = !::renderStarsOn; // toggle stars if (k == '*') ::renderStarsOn = !::renderStarsOn; // toggle stars
if (k == 'V' || k == 'v') ::renderVoxels = !::renderVoxels; // toggle voxels if (k == 'V' || k == 'v') ::renderVoxels = !::renderVoxels; // toggle voxels
@ -1675,6 +1641,12 @@ void key(unsigned char k, int x, int y) {
::lookingInMirror = !::lookingInMirror; ::lookingInMirror = !::lookingInMirror;
#ifndef _WIN32 #ifndef _WIN32
audio.setMixerLoopbackFlag(::lookingInMirror); audio.setMixerLoopbackFlag(::lookingInMirror);
if (::lookingInMirror) {
myCamera.setMode(CAMERA_MODE_MIRROR);
} else {
myCamera.setMode(defaultCameraMode);
}
#endif #endif
} }
@ -1834,7 +1806,7 @@ void idle(void) {
} }
// Read serial port interface devices // Read serial port interface devices
if (serialPort.active && USING_INVENSENSE_MPU9150) { if (serialPort.active) {
serialPort.readData(); serialPort.readData();
} }
@ -1868,10 +1840,6 @@ void idle(void) {
lastTimeIdle = check; lastTimeIdle = check;
} }
// Read serial data
if (serialPort.active && !USING_INVENSENSE_MPU9150) {
serialPort.readData();
}
} }
void reshape(int width, int height) { void reshape(int width, int height) {
@ -1944,14 +1912,18 @@ glm::vec3 getGravity(glm::vec3 pos) {
return glm::vec3(0.f, 0.f, 0.f); return glm::vec3(0.f, 0.f, 0.f);
} }
} }
void mouseFunc(int button, int state, int x, int y) { void mouseFunc(int button, int state, int x, int y) {
mouseX = x; //catch mouse actions on the menu
mouseY = y; bool menuClickedOrUnclicked = menu.mouseClick(x, y);
switch (button) { if (!menuClickedOrUnclicked) {
case GLUT_LEFT_BUTTON: if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN && !menu.mouseClick(x, y)) { mouseX = x;
mouseY = y;
if (state == GLUT_DOWN) {
mousePressed = 1; mousePressed = 1;
if (::mouseMode == ADD_VOXEL_MODE || ::mouseMode == COLOR_VOXEL_MODE) { if (::mouseMode == ADD_VOXEL_MODE || ::mouseMode == COLOR_VOXEL_MODE) {
addVoxelUnderCursor(); addVoxelUnderCursor();
@ -1959,19 +1931,16 @@ void mouseFunc(int button, int state, int x, int y) {
} else { // ::mouseMode == DELETE_VOXEL_MODE } else { // ::mouseMode == DELETE_VOXEL_MODE
deleteVoxelUnderCursor(); deleteVoxelUnderCursor();
} }
} else { } else if (state == GLUT_UP) {
mousePressed = 0; mousePressed = 0;
} }
break; } else if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) {
deleteVoxelUnderCursor();
case GLUT_RIGHT_BUTTON: }
if (state == GLUT_DOWN) {
deleteVoxelUnderCursor();
}
break;
} }
} }
void motionFunc(int x, int y) { void motionFunc(int x, int y) {
mouseX = x; mouseX = x;
mouseY = y; mouseY = y;
@ -1997,6 +1966,10 @@ void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) {
#endif #endif
int main(int argc, const char * argv[]) { int main(int argc, const char * argv[]) {
gettimeofday(&applicationStartupTime, NULL);
printLog("Interface Startup:\n");
voxels.setViewFrustum(&::viewFrustum); voxels.setViewFrustum(&::viewFrustum);
shared_lib::printLog = & ::printLog; shared_lib::printLog = & ::printLog;
@ -2014,7 +1987,6 @@ int main(int argc, const char * argv[]) {
AgentList::getInstance()->getAgentSocket().setBlocking(false); AgentList::getInstance()->getAgentSocket().setBlocking(false);
} }
gettimeofday(&applicationStartupTime, NULL);
const char* domainIP = getCmdOption(argc, argv, "--domain"); const char* domainIP = getCmdOption(argc, argv, "--domain");
if (domainIP) { if (domainIP) {
strcpy(DOMAIN_IP,domainIP); strcpy(DOMAIN_IP,domainIP);
@ -2051,13 +2023,17 @@ int main(int argc, const char * argv[]) {
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(WIDTH, HEIGHT); glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("Interface"); glutCreateWindow("Interface");
printLog( "Created Display Window.\n" );
#ifdef _WIN32 #ifdef _WIN32
glewInit(); glewInit();
printLog( "Glew Init complete.\n" );
#endif #endif
// we need to create a QApplication instance in order to use Qt's font rendering // we need to create a QApplication instance in order to use Qt's font rendering
app = new QApplication(argc, const_cast<char**>(argv)); app = new QApplication(argc, const_cast<char**>(argv));
printLog( "Created QT Application.\n" );
// Before we render anything, let's set up our viewFrustumOffsetCamera with a sufficiently large // Before we render anything, let's set up our viewFrustumOffsetCamera with a sufficiently large
// field of view and near and far clip to make it interesting. // field of view and near and far clip to make it interesting.
@ -2065,11 +2041,9 @@ int main(int argc, const char * argv[]) {
viewFrustumOffsetCamera.setNearClip(0.1); viewFrustumOffsetCamera.setNearClip(0.1);
viewFrustumOffsetCamera.setFarClip(500.0*TREE_SCALE); viewFrustumOffsetCamera.setFarClip(500.0*TREE_SCALE);
printLog( "Created Display Window.\n" );
initMenu(); initMenu();
initDisplay(); initDisplay();
printLog( "Initialized Display.\n" );
glutDisplayFunc(display); glutDisplayFunc(display);
glutReshapeFunc(reshape); glutReshapeFunc(reshape);
@ -2081,6 +2055,8 @@ int main(int argc, const char * argv[]) {
glutPassiveMotionFunc(mouseoverFunc); glutPassiveMotionFunc(mouseoverFunc);
glutMouseFunc(mouseFunc); glutMouseFunc(mouseFunc);
glutIdleFunc(idle); glutIdleFunc(idle);
printLog( "Initialized Display.\n" );
init(); init();
printLog( "Init() complete.\n" ); printLog( "Init() complete.\n" );

View file

@ -50,7 +50,7 @@ namespace starfield {
return false; return false;
} }
printLog("Stars.cpp: read %u vertices, using %lu\n", _valRecordsRead, _ptrVertices->size()); printLog("Loaded %u stars.\n", _valRecordsRead);
return true; return true;
} }

View file

@ -42,6 +42,8 @@ AvatarData::AvatarData() :
_headYaw(0), _headYaw(0),
_headPitch(0), _headPitch(0),
_headRoll(0), _headRoll(0),
_headLeanSideways(0),
_headLeanForward(0),
_handState(0), _handState(0),
_cameraPosition(0,0,0), _cameraPosition(0,0,0),
_cameraDirection(0,0,0), _cameraDirection(0,0,0),
@ -84,7 +86,13 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headPitch); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headPitch);
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headRoll); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headRoll);
// Hand Position // Head lean X,Z (head lateral and fwd/back motion relative to torso)
memcpy(destinationBuffer, &_headLeanSideways, sizeof(float));
destinationBuffer += sizeof(float);
memcpy(destinationBuffer, &_headLeanForward, sizeof(float));
destinationBuffer += sizeof(float);
// Hand Position
memcpy(destinationBuffer, &_handPosition, sizeof(float) * 3); memcpy(destinationBuffer, &_handPosition, sizeof(float) * 3);
destinationBuffer += sizeof(float) * 3; destinationBuffer += sizeof(float) * 3;
@ -150,6 +158,12 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headPitch); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headPitch);
sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headRoll); sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t *)sourceBuffer, &_headRoll);
// Head position relative to pelvis
memcpy(&_headLeanSideways, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float);
memcpy(&_headLeanForward, sourceBuffer, sizeof(float));
sourceBuffer += sizeof(float);
// Hand Position // Hand Position
memcpy(&_handPosition, sourceBuffer, sizeof(float) * 3); memcpy(&_handPosition, sourceBuffer, sizeof(float) * 3);
sourceBuffer += sizeof(float) * 3; sourceBuffer += sizeof(float) * 3;

View file

@ -55,6 +55,12 @@ public:
void addHeadYaw(float y){_headYaw -= y; } void addHeadYaw(float y){_headYaw -= y; }
void addHeadRoll(float r){_headRoll += r; } void addHeadRoll(float r){_headRoll += r; }
// Head vector deflection from pelvix in X,Z
void setHeadLeanSideways(float s) {_headLeanSideways = s; };
float getHeadLeanSideways() const { return _headLeanSideways; };
void setHeadLeanForward(float f) {_headLeanForward = f; };
float getHeadLeanForward() const { return _headLeanForward; };
// Hand State // Hand State
void setHandState(char s) { _handState = s; }; void setHandState(char s) { _handState = s; };
char getHandState() const {return _handState; }; char getHandState() const {return _handState; };
@ -104,6 +110,9 @@ protected:
float _headYaw; float _headYaw;
float _headPitch; float _headPitch;
float _headRoll; float _headRoll;
float _headLeanSideways;
float _headLeanForward;
// Audio loudness (used to drive facial animation) // Audio loudness (used to drive facial animation)
float _audioLoudness; float _audioLoudness;

View file

@ -254,15 +254,13 @@ void Agent::printLog(Agent const& agent) {
char publicAddressBuffer[16] = {'\0'}; char publicAddressBuffer[16] = {'\0'};
unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, agent.publicSocket); unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, agent.publicSocket);
char localAddressBuffer[16] = {'\0'}; //char localAddressBuffer[16] = {'\0'};
unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, agent.localSocket); //unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, agent.localSocket);
::printLog("ID: %d T: %s (%c) PA: %s:%d LA: %s:%d\n", ::printLog("# %d %s (%c) @ %s:%d\n",
agent.agentId, agent.agentId,
agent.getTypeName(), agent.getTypeName(),
agent.type, agent.type,
publicAddressBuffer, publicAddressBuffer,
publicAddressPort, publicAddressPort);
localAddressBuffer,
localAddressPort);
} }

View file

@ -284,7 +284,7 @@ void AgentList::addAgentToList(Agent* newAgent) {
++_numAgents; ++_numAgents;
printLog("Added agent - "); printLog("Added ");
Agent::printLog(*newAgent); Agent::printLog(*newAgent);
} }
@ -377,7 +377,7 @@ void *removeSilentAgents(void *args) {
if ((checkTimeUSecs - agent->getLastHeardMicrostamp()) > AGENT_SILENCE_THRESHOLD_USECS if ((checkTimeUSecs - agent->getLastHeardMicrostamp()) > AGENT_SILENCE_THRESHOLD_USECS
&& agent->getType() != AGENT_TYPE_VOXEL) { && agent->getType() != AGENT_TYPE_VOXEL) {
printLog("Killing agent - "); printLog("Killed ");
Agent::printLog(*agent); Agent::printLog(*agent);
agent->setAlive(false); agent->setAlive(false);
@ -416,12 +416,12 @@ void *checkInWithDomainServer(void *args) {
sockaddr_in tempAddress; sockaddr_in tempAddress;
memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length);
strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr)); strcpy(DOMAIN_IP, inet_ntoa(tempAddress.sin_addr));
printLog("Domain server: %s - %s\n", DOMAIN_HOSTNAME, DOMAIN_IP); printLog("Domain Server: %s \n", DOMAIN_HOSTNAME);
} else { } else {
printLog("Failed lookup domainserver\n"); printLog("Failed lookup domainserver\n");
} }
} else printLog("Using static domainserver IP: %s\n", DOMAIN_IP); } else printLog("Domain Server IP: %s\n", DOMAIN_IP);
AgentList* parentAgentList = (AgentList*) args; AgentList* parentAgentList = (AgentList*) args;

View file

@ -10,118 +10,63 @@
#include "AudioRingBuffer.h" #include "AudioRingBuffer.h"
AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) : AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) :
ringBufferLengthSamples(ringSamples), _ringBufferLengthSamples(ringSamples),
bufferLengthSamples(bufferSamples), _bufferLengthSamples(bufferSamples),
endOfLastWrite(NULL), _endOfLastWrite(NULL),
started(false), _started(false),
_shouldBeAddedToMix(false), _shouldBeAddedToMix(false),
_shouldLoopbackForAgent(false) { _shouldLoopbackForAgent(false) {
buffer = new int16_t[ringBufferLengthSamples];
nextOutput = buffer; _buffer = new int16_t[_ringBufferLengthSamples];
_nextOutput = _buffer;
}; };
AudioRingBuffer::AudioRingBuffer(const AudioRingBuffer &otherRingBuffer) { AudioRingBuffer::AudioRingBuffer(const AudioRingBuffer &otherRingBuffer) {
ringBufferLengthSamples = otherRingBuffer.ringBufferLengthSamples; _ringBufferLengthSamples = otherRingBuffer._ringBufferLengthSamples;
bufferLengthSamples = otherRingBuffer.bufferLengthSamples; _bufferLengthSamples = otherRingBuffer._bufferLengthSamples;
started = otherRingBuffer.started; _started = otherRingBuffer._started;
_shouldBeAddedToMix = otherRingBuffer._shouldBeAddedToMix; _shouldBeAddedToMix = otherRingBuffer._shouldBeAddedToMix;
_shouldLoopbackForAgent = otherRingBuffer._shouldLoopbackForAgent; _shouldLoopbackForAgent = otherRingBuffer._shouldLoopbackForAgent;
buffer = new int16_t[ringBufferLengthSamples]; _buffer = new int16_t[_ringBufferLengthSamples];
memcpy(buffer, otherRingBuffer.buffer, sizeof(int16_t) * ringBufferLengthSamples); memcpy(_buffer, otherRingBuffer._buffer, sizeof(int16_t) * _ringBufferLengthSamples);
nextOutput = buffer + (otherRingBuffer.nextOutput - otherRingBuffer.buffer); _nextOutput = _buffer + (otherRingBuffer._nextOutput - otherRingBuffer._buffer);
endOfLastWrite = buffer + (otherRingBuffer.endOfLastWrite - otherRingBuffer.buffer); _endOfLastWrite = _buffer + (otherRingBuffer._endOfLastWrite - otherRingBuffer._buffer);
} }
AudioRingBuffer::~AudioRingBuffer() { AudioRingBuffer::~AudioRingBuffer() {
delete[] buffer; delete[] _buffer;
}; };
AudioRingBuffer* AudioRingBuffer::clone() const { AudioRingBuffer* AudioRingBuffer::clone() const {
return new AudioRingBuffer(*this); return new AudioRingBuffer(*this);
} }
int16_t* AudioRingBuffer::getNextOutput() {
return nextOutput;
}
void AudioRingBuffer::setNextOutput(int16_t *newPointer) {
nextOutput = newPointer;
}
int16_t* AudioRingBuffer::getEndOfLastWrite() {
return endOfLastWrite;
}
void AudioRingBuffer::setEndOfLastWrite(int16_t *newPointer) {
endOfLastWrite = newPointer;
}
int16_t* AudioRingBuffer::getBuffer() {
return buffer;
}
bool AudioRingBuffer::isStarted() {
return started;
}
void AudioRingBuffer::setStarted(bool status) {
started = status;
}
float* AudioRingBuffer::getPosition() {
return position;
}
void AudioRingBuffer::setPosition(float *newPosition) {
position[0] = newPosition[0];
position[1] = newPosition[1];
position[2] = newPosition[2];
}
float AudioRingBuffer::getAttenuationRatio() {
return attenuationRatio;
}
void AudioRingBuffer::setAttenuationRatio(float newAttenuation) {
attenuationRatio = newAttenuation;
}
float AudioRingBuffer::getBearing() {
return bearing;
}
void AudioRingBuffer::setBearing(float newBearing) {
bearing = newBearing;
}
const int AGENT_LOOPBACK_MODIFIER = 307; const int AGENT_LOOPBACK_MODIFIER = 307;
int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
if (numBytes > (bufferLengthSamples * sizeof(int16_t))) { if (numBytes > (_bufferLengthSamples * sizeof(int16_t))) {
unsigned char *dataPtr = sourceBuffer + 1; unsigned char *dataPtr = sourceBuffer + 1;
for (int p = 0; p < 3; p ++) { memcpy(&_position, dataPtr, sizeof(_position));
memcpy(&position[p], dataPtr, sizeof(float)); dataPtr += (sizeof(_position));
dataPtr += sizeof(float);
}
unsigned int attenuationByte = *(dataPtr++); unsigned int attenuationByte = *(dataPtr++);
attenuationRatio = attenuationByte / 255.0f; _attenuationRatio = attenuationByte / 255.0f;
memcpy(&bearing, dataPtr, sizeof(float)); memcpy(&_bearing, dataPtr, sizeof(float));
dataPtr += sizeof(bearing); dataPtr += sizeof(_bearing);
if (bearing > 180 || bearing < -180) { if (_bearing > 180 || _bearing < -180) {
// we were passed an invalid bearing because this agent wants loopback (pressed the H key) // we were passed an invalid bearing because this agent wants loopback (pressed the H key)
_shouldLoopbackForAgent = true; _shouldLoopbackForAgent = true;
// correct the bearing // correct the bearing
bearing = bearing > 0 _bearing = _bearing > 0
? bearing - AGENT_LOOPBACK_MODIFIER ? _bearing - AGENT_LOOPBACK_MODIFIER
: bearing + AGENT_LOOPBACK_MODIFIER; : _bearing + AGENT_LOOPBACK_MODIFIER;
} else { } else {
_shouldLoopbackForAgent = false; _shouldLoopbackForAgent = false;
} }
@ -129,33 +74,33 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
sourceBuffer = dataPtr; sourceBuffer = dataPtr;
} }
if (endOfLastWrite == NULL) { if (!_endOfLastWrite) {
endOfLastWrite = buffer; _endOfLastWrite = _buffer;
} else if (diffLastWriteNextOutput() > ringBufferLengthSamples - bufferLengthSamples) { } else if (diffLastWriteNextOutput() > _ringBufferLengthSamples - _bufferLengthSamples) {
endOfLastWrite = buffer; _endOfLastWrite = _buffer;
nextOutput = buffer; _nextOutput = _buffer;
started = false; _started = false;
} }
memcpy(endOfLastWrite, sourceBuffer, bufferLengthSamples * sizeof(int16_t)); memcpy(_endOfLastWrite, sourceBuffer, _bufferLengthSamples * sizeof(int16_t));
endOfLastWrite += bufferLengthSamples; _endOfLastWrite += _bufferLengthSamples;
if (endOfLastWrite >= buffer + ringBufferLengthSamples) { if (_endOfLastWrite >= _buffer + _ringBufferLengthSamples) {
endOfLastWrite = buffer; _endOfLastWrite = _buffer;
} }
return numBytes; return numBytes;
} }
short AudioRingBuffer::diffLastWriteNextOutput() { short AudioRingBuffer::diffLastWriteNextOutput() {
if (endOfLastWrite == NULL) { if (!_endOfLastWrite) {
return 0; return 0;
} else { } else {
short sampleDifference = endOfLastWrite - nextOutput; short sampleDifference = _endOfLastWrite - _nextOutput;
if (sampleDifference < 0) { if (sampleDifference < 0) {
sampleDifference += ringBufferLengthSamples; sampleDifference += _ringBufferLengthSamples;
} }
return sampleDifference; return sampleDifference;

View file

@ -12,6 +12,12 @@
#include <stdint.h> #include <stdint.h>
#include "AgentData.h" #include "AgentData.h"
struct Position {
float x;
float y;
float z;
};
class AudioRingBuffer : public AgentData { class AudioRingBuffer : public AgentData {
public: public:
AudioRingBuffer(int ringSamples, int bufferSamples); AudioRingBuffer(int ringSamples, int bufferSamples);
@ -21,35 +27,36 @@ public:
int parseData(unsigned char* sourceBuffer, int numBytes); int parseData(unsigned char* sourceBuffer, int numBytes);
AudioRingBuffer* clone() const; AudioRingBuffer* clone() const;
int16_t* getNextOutput(); int16_t* getNextOutput() const { return _nextOutput; }
void setNextOutput(int16_t *newPointer); void setNextOutput(int16_t* nextOutput) { _nextOutput = nextOutput; }
int16_t* getEndOfLastWrite();
void setEndOfLastWrite(int16_t *newPointer); int16_t* getEndOfLastWrite() const { return _endOfLastWrite; }
int16_t* getBuffer(); void setEndOfLastWrite(int16_t* endOfLastWrite) { _endOfLastWrite = endOfLastWrite; }
bool isStarted();
void setStarted(bool status); int16_t* getBuffer() const { return _buffer; }
bool isStarted() const { return _started; }
void setStarted(bool started) { _started = started; }
bool shouldBeAddedToMix() const { return _shouldBeAddedToMix; } bool shouldBeAddedToMix() const { return _shouldBeAddedToMix; }
void setShouldBeAddedToMix(bool shouldBeAddedToMix) { _shouldBeAddedToMix = shouldBeAddedToMix; } void setShouldBeAddedToMix(bool shouldBeAddedToMix) { _shouldBeAddedToMix = shouldBeAddedToMix; }
float* getPosition();
void setPosition(float newPosition[]);
float getAttenuationRatio();
void setAttenuationRatio(float newAttenuation);
float getBearing();
void setBearing(float newBearing);
const Position& getPosition() const { return _position; }
float getAttenuationRatio() const { return _attenuationRatio; }
float getBearing() const { return _bearing; }
bool shouldLoopbackForAgent() const { return _shouldLoopbackForAgent; } bool shouldLoopbackForAgent() const { return _shouldLoopbackForAgent; }
short diffLastWriteNextOutput(); short diffLastWriteNextOutput();
private: private:
int ringBufferLengthSamples; int _ringBufferLengthSamples;
int bufferLengthSamples; int _bufferLengthSamples;
float position[3]; Position _position;
float attenuationRatio; float _attenuationRatio;
float bearing; float _bearing;
int16_t *nextOutput; int16_t* _nextOutput;
int16_t *endOfLastWrite; int16_t* _endOfLastWrite;
int16_t *buffer; int16_t* _buffer;
bool started; bool _started;
bool _shouldBeAddedToMix; bool _shouldBeAddedToMix;
bool _shouldLoopbackForAgent; bool _shouldLoopbackForAgent;
}; };

View file

@ -96,6 +96,7 @@ void UrlReader::getinfo(char const*& url,
if (time > s.st_mtime) { if (time > s.st_mtime) {
// file on server is newer -> update cache file // file on server is newer -> update cache file
_ptrCacheFile = fopen(_strCacheFile, "wb"); _ptrCacheFile = fopen(_strCacheFile, "wb");
printf("From URL: ");
if (_ptrCacheFile != 0l) { if (_ptrCacheFile != 0l) {
_valCacheMode = cache_write; _valCacheMode = cache_write;
} }
@ -108,6 +109,7 @@ void UrlReader::getinfo(char const*& url,
} }
} }
_ptrCacheFile = fopen(_strCacheFile, "rb"); _ptrCacheFile = fopen(_strCacheFile, "rb");
printf("From file: ");
if (_ptrCacheFile != 0l) { if (_ptrCacheFile != 0l) {
_valCacheMode = cache_read; _valCacheMode = cache_read;
} }

View file

@ -94,6 +94,7 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) {
VoxelNode* returnedChild = _children[childIndex]; VoxelNode* returnedChild = _children[childIndex];
if (_children[childIndex]) { if (_children[childIndex]) {
_children[childIndex] = NULL; _children[childIndex] = NULL;
_isDirty = true;
} }
return returnedChild; return returnedChild;
} }
@ -150,9 +151,7 @@ void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) {
_currentColor[1] = green; _currentColor[1] = green;
_currentColor[2] = blue; _currentColor[2] = blue;
_currentColor[3] = 1; // XXXBHG - False colors are always considered set _currentColor[3] = 1; // XXXBHG - False colors are always considered set
//if (_shouldRender) { _isDirty = true;
_isDirty = true;
//}
} }
} }
@ -163,9 +162,7 @@ void VoxelNode::setFalseColored(bool isFalseColored) {
memcpy(&_currentColor,&_trueColor,sizeof(nodeColor)); memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
} }
_falseColored = isFalseColored; _falseColored = isFalseColored;
//if (_shouldRender) { _isDirty = true;
_isDirty = true;
//}
} }
}; };

View file

@ -61,6 +61,7 @@ public:
bool isDirty() const { return _isDirty; }; bool isDirty() const { return _isDirty; };
void clearDirtyBit() { _isDirty = false; }; void clearDirtyBit() { _isDirty = false; };
void setDirtyBit() { _isDirty = true; };
unsigned long int getNodesChangedFromBitstream() const { return _nodesChangedFromBitstream; }; unsigned long int getNodesChangedFromBitstream() const { return _nodesChangedFromBitstream; };
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,