Merge branch 'master' of https://github.com/worklist/hifi
Conflicts: libraries/shared/src/PacketHeaders.h
|
@ -16,10 +16,14 @@
|
|||
#include <errno.h>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <signal.h>
|
||||
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <StdDev.h>
|
||||
#include <Stacktrace.h>
|
||||
|
||||
#include "AudioRingBuffer.h"
|
||||
#include "PacketHeaders.h"
|
||||
|
||||
|
@ -56,11 +60,8 @@ const float DISTANCE_RATIO = 3.0f / 0.3f;
|
|||
const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5;
|
||||
const int PHASE_DELAY_AT_90 = 20;
|
||||
|
||||
const int AGENT_LOOPBACK_MODIFIER = 307;
|
||||
|
||||
const int LOOPBACK_SANITY_CHECK = 0;
|
||||
|
||||
StDev stdev;
|
||||
const float MAX_OFF_AXIS_ATTENUATION = 0.5f;
|
||||
const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f;
|
||||
|
||||
void plateauAdditionOfSamples(int16_t &mixSample, int16_t sampleToAdd) {
|
||||
long sumSample = sampleToAdd + mixSample;
|
||||
|
@ -71,8 +72,7 @@ void plateauAdditionOfSamples(int16_t &mixSample, int16_t sampleToAdd) {
|
|||
mixSample = normalizedSample;
|
||||
}
|
||||
|
||||
void *sendBuffer(void *args)
|
||||
{
|
||||
void *sendBuffer(void *args) {
|
||||
int sentBytes;
|
||||
int nextFrame = 0;
|
||||
timeval startTime;
|
||||
|
@ -106,115 +106,117 @@ void *sendBuffer(void *args)
|
|||
}
|
||||
|
||||
int numAgents = agentList->size();
|
||||
float distanceCoeffs[numAgents][numAgents];
|
||||
memset(distanceCoeffs, 0, sizeof(distanceCoeffs));
|
||||
float distanceCoefficients[numAgents][numAgents];
|
||||
memset(distanceCoefficients, 0, sizeof(distanceCoefficients));
|
||||
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
AudioRingBuffer* agentRingBuffer = (AudioRingBuffer*) agent->getLinkedData();
|
||||
float agentBearing = agentRingBuffer->getBearing();
|
||||
bool agentWantsLoopback = false;
|
||||
|
||||
if (agentBearing > 180 || agentBearing < -180) {
|
||||
// we were passed an invalid bearing because this agent wants loopback (pressed the H key)
|
||||
agentWantsLoopback = true;
|
||||
|
||||
// correct the bearing
|
||||
agentBearing = agentBearing > 0
|
||||
? agentBearing - AGENT_LOOPBACK_MODIFIER
|
||||
: agentBearing + AGENT_LOOPBACK_MODIFIER;
|
||||
}
|
||||
|
||||
int16_t clientMix[BUFFER_LENGTH_SAMPLES_PER_CHANNEL * 2] = {};
|
||||
|
||||
|
||||
for (AgentList::iterator otherAgent = agentList->begin(); otherAgent != agentList->end(); otherAgent++) {
|
||||
if (otherAgent != agent || (otherAgent == agent && agentWantsLoopback)) {
|
||||
if (otherAgent != agent || (otherAgent == agent && agentRingBuffer->shouldLoopbackForAgent())) {
|
||||
AudioRingBuffer* otherAgentBuffer = (AudioRingBuffer*) otherAgent->getLinkedData();
|
||||
|
||||
if (otherAgentBuffer->shouldBeAddedToMix()) {
|
||||
float *agentPosition = agentRingBuffer->getPosition();
|
||||
float *otherAgentPosition = otherAgentBuffer->getPosition();
|
||||
|
||||
float bearingRelativeAngleToSource = 0.f;
|
||||
float attenuationCoefficient = 1.f;
|
||||
int numSamplesDelay = 0;
|
||||
float weakChannelAmplitudeRatio = 1.f;
|
||||
|
||||
// calculate the distance to the other agent
|
||||
|
||||
// use the distance to the other agent to calculate the change in volume for this frame
|
||||
int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
||||
int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
||||
|
||||
if (distanceCoeffs[lowAgentIndex][highAgentIndex] == 0) {
|
||||
float distanceToAgent = sqrtf(powf(agentPosition[0] - otherAgentPosition[0], 2) +
|
||||
powf(agentPosition[1] - otherAgentPosition[1], 2) +
|
||||
powf(agentPosition[2] - otherAgentPosition[2], 2));
|
||||
if (otherAgent != agent) {
|
||||
float *agentPosition = agentRingBuffer->getPosition();
|
||||
float *otherAgentPosition = otherAgentBuffer->getPosition();
|
||||
|
||||
float minCoefficient = std::min(1.0f,
|
||||
powf(0.5, (logf(DISTANCE_RATIO * distanceToAgent) / logf(3)) - 1));
|
||||
distanceCoeffs[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 angleToSource;
|
||||
|
||||
|
||||
// find the angle we need for calculation based on the orientation of the triangle
|
||||
if (otherAgentPosition[0] > agentPosition[0]) {
|
||||
if (otherAgentPosition[2] > agentPosition[2]) {
|
||||
angleToSource = -90 + triangleAngle - agentBearing;
|
||||
} else {
|
||||
angleToSource = -90 - triangleAngle - agentBearing;
|
||||
// calculate the distance to the other agent
|
||||
|
||||
// use the distance to the other agent to calculate the change in volume for this frame
|
||||
int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex());
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (otherAgentPosition[2] > agentPosition[2]) {
|
||||
angleToSource = 90 - triangleAngle - agentBearing;
|
||||
|
||||
|
||||
// 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;
|
||||
float 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 {
|
||||
angleToSource = 90 + triangleAngle - agentBearing;
|
||||
if (otherAgentPosition[2] > agentPosition[2]) {
|
||||
absoluteAngleToSource = 90 - triangleAngle;
|
||||
} else {
|
||||
absoluteAngleToSource = 90 + triangleAngle;
|
||||
}
|
||||
}
|
||||
|
||||
if (absoluteAngleToSource > 180) {
|
||||
absoluteAngleToSource -= 360;
|
||||
} else if (absoluteAngleToSource < -180) {
|
||||
absoluteAngleToSource += 360;
|
||||
}
|
||||
|
||||
bearingRelativeAngleToSource = absoluteAngleToSource - agentBearing;
|
||||
bearingRelativeAngleToSource *= (M_PI / 180);
|
||||
|
||||
float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing();
|
||||
|
||||
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;
|
||||
|
||||
float sinRatio = fabsf(sinf(bearingRelativeAngleToSource));
|
||||
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
|
||||
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
||||
}
|
||||
|
||||
if (angleToSource > 180) {
|
||||
angleToSource -= 360;
|
||||
} else if (angleToSource < -180) {
|
||||
angleToSource += 360;
|
||||
}
|
||||
|
||||
angleToSource *= (M_PI / 180);
|
||||
|
||||
float sinRatio = fabsf(sinf(angleToSource));
|
||||
int numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
|
||||
float weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
||||
|
||||
int16_t *goodChannel = angleToSource > 0 ? clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL : clientMix;
|
||||
int16_t *delayedChannel = angleToSource > 0 ? clientMix : clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
|
||||
int16_t *delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer()
|
||||
? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay
|
||||
: otherAgentBuffer->getNextOutput() - numSamplesDelay;
|
||||
|
||||
int16_t* goodChannel = bearingRelativeAngleToSource > 0 ? clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL : clientMix;
|
||||
int16_t* delayedChannel = bearingRelativeAngleToSource > 0 ? clientMix : clientMix + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||
|
||||
int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer()
|
||||
? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay
|
||||
: otherAgentBuffer->getNextOutput() - numSamplesDelay;
|
||||
|
||||
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
||||
|
||||
if (s < numSamplesDelay) {
|
||||
// pull the earlier sample for the delayed channel
|
||||
|
||||
int earlierSample = delaySamplePointer[s] *
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex] *
|
||||
otherAgentBuffer->getAttenuationRatio();
|
||||
|
||||
int earlierSample = delaySamplePointer[s] * attenuationCoefficient;
|
||||
plateauAdditionOfSamples(delayedChannel[s], earlierSample * weakChannelAmplitudeRatio);
|
||||
}
|
||||
|
||||
int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] *
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex] *
|
||||
otherAgentBuffer->getAttenuationRatio());
|
||||
int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient);
|
||||
plateauAdditionOfSamples(goodChannel[s], currentSample);
|
||||
|
||||
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
|
||||
plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay],
|
||||
currentSample *
|
||||
weakChannelAmplitudeRatio *
|
||||
otherAgentBuffer->getAttenuationRatio());
|
||||
weakChannelAmplitudeRatio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -255,11 +257,12 @@ void attachNewBufferToAgent(Agent *newAgent) {
|
|||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT);
|
||||
int main(int argc, const char* argv[]) {
|
||||
signal(SIGSEGV, printStacktrace);
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_MIXER, MIXER_LISTEN_PORT);
|
||||
|
||||
ssize_t receivedBytes = 0;
|
||||
|
||||
agentList->linkedDataCreateCallback = attachNewBufferToAgent;
|
||||
|
@ -272,49 +275,17 @@ int main(int argc, const char * argv[])
|
|||
pthread_t sendBufferThread;
|
||||
pthread_create(&sendBufferThread, NULL, sendBuffer, NULL);
|
||||
|
||||
int16_t *loopbackAudioPacket;
|
||||
if (LOOPBACK_SANITY_CHECK) {
|
||||
loopbackAudioPacket = new int16_t[1024];
|
||||
}
|
||||
|
||||
sockaddr *agentAddress = new sockaddr;
|
||||
timeval lastReceive;
|
||||
gettimeofday(&lastReceive, NULL);
|
||||
|
||||
bool firstSample = true;
|
||||
|
||||
while (true) {
|
||||
if(agentList->getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) {
|
||||
if (packetData[0] == PACKET_HEADER_INJECT_AUDIO) {
|
||||
|
||||
// Compute and report standard deviation for jitter calculation
|
||||
if (firstSample) {
|
||||
stdev.reset();
|
||||
firstSample = false;
|
||||
} else {
|
||||
double tDiff = (usecTimestampNow() - usecTimestamp(&lastReceive)) / 1000;
|
||||
stdev.addValue(tDiff);
|
||||
|
||||
if (stdev.getSamples() > 500) {
|
||||
//printf("Avg: %4.2f, Stdev: %4.2f\n", stdev.getAverage(), stdev.getStDev());
|
||||
stdev.reset();
|
||||
}
|
||||
|
||||
if (agentList->addOrUpdateAgent(agentAddress, agentAddress, packetData[0], agentList->getLastAgentId())) {
|
||||
agentList->increaseAgentId();
|
||||
}
|
||||
|
||||
gettimeofday(&lastReceive, NULL);
|
||||
|
||||
// add or update the existing interface agent
|
||||
if (!LOOPBACK_SANITY_CHECK) {
|
||||
|
||||
if (agentList->addOrUpdateAgent(agentAddress, agentAddress, packetData[0], agentList->getLastAgentId())) {
|
||||
agentList->increaseAgentId();
|
||||
}
|
||||
|
||||
agentList->updateAgentWithData(agentAddress, packetData, receivedBytes);
|
||||
} else {
|
||||
memcpy(loopbackAudioPacket, packetData + 1 + (sizeof(float) * 4), 1024);
|
||||
agentList->getAgentSocket().send(agentAddress, loopbackAudioPacket, 1024);
|
||||
}
|
||||
agentList->updateAgentWithData(agentAddress, packetData, receivedBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,8 +51,7 @@ void attachAvatarDataToAgent(Agent *newAgent) {
|
|||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
int main(int argc, const char* argv[]) {
|
||||
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AVATAR_MIXER, AVATAR_LISTEN_PORT);
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
|
@ -69,17 +68,20 @@ int main(int argc, const char* argv[])
|
|||
*broadcastPacket = PACKET_HEADER_BULK_AVATAR_DATA;
|
||||
|
||||
unsigned char* currentBufferPosition = NULL;
|
||||
|
||||
uint16_t agentID = 0;
|
||||
|
||||
while (true) {
|
||||
if (agentList->getAgentSocket().receive(agentAddress, packetData, &receivedBytes)) {
|
||||
switch (packetData[0]) {
|
||||
case PACKET_HEADER_HEAD_DATA:
|
||||
// add this agent if we don't have them yet
|
||||
if (agentList->addOrUpdateAgent(agentAddress, agentAddress, AGENT_TYPE_AVATAR, agentList->getLastAgentId())) {
|
||||
agentList->increaseAgentId();
|
||||
}
|
||||
// grab the agent ID from the packet
|
||||
unpackAgentId(packetData + 1, &agentID);
|
||||
|
||||
// this is positional data from an agent
|
||||
// add or update the agent in our list
|
||||
agentList->addOrUpdateAgent(agentAddress, agentAddress, AGENT_TYPE_AVATAR, agentID);
|
||||
|
||||
// parse positional data from an agent
|
||||
agentList->updateAgentWithData(agentAddress, packetData, receivedBytes);
|
||||
|
||||
currentBufferPosition = broadcastPacket + 1;
|
||||
|
|
|
@ -86,7 +86,6 @@ int main(int argc, const char * argv[])
|
|||
|
||||
unsigned char* currentBufferPos;
|
||||
unsigned char* startPointer;
|
||||
int packetBytesWithoutLeadingChar;
|
||||
|
||||
sockaddr_in agentPublicAddress, agentLocalAddress;
|
||||
agentLocalAddress.sin_family = AF_INET;
|
||||
|
@ -95,12 +94,15 @@ int main(int argc, const char * argv[])
|
|||
|
||||
agentList->startSilentAgentRemovalThread();
|
||||
|
||||
uint16_t packetAgentID = 0;
|
||||
|
||||
while (true) {
|
||||
if (agentList->getAgentSocket().receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes)) {
|
||||
if (agentList->getAgentSocket().receive((sockaddr *)&agentPublicAddress, packetData, &receivedBytes) &&
|
||||
(packetData[0] == PACKET_HEADER_DOMAIN_RFD || packetData[0] == PACKET_HEADER_DOMAIN_LIST_REQUEST)) {
|
||||
std::map<char, Agent *> newestSoloAgents;
|
||||
|
||||
agentType = packetData[1];
|
||||
unpackSocket(&packetData[2], (sockaddr*) &agentLocalAddress);
|
||||
unpackSocket(packetData + 2, (sockaddr*) &agentLocalAddress);
|
||||
|
||||
// check the agent public address
|
||||
// if it matches our local address we're on the same box
|
||||
|
@ -118,14 +120,9 @@ int main(int argc, const char * argv[])
|
|||
agentType,
|
||||
agentList->getLastAgentId())) {
|
||||
agentList->increaseAgentId();
|
||||
} else if (packetData[0] == PACKET_HEADER_DOMAIN_RFD) {
|
||||
// if this is a previous agent, and they are re-reporting for duty
|
||||
// then we need to update the first receive time
|
||||
Agent* refreshedAgent = agentList->agentWithAddress((sockaddr*) &agentLocalAddress);
|
||||
refreshedAgent->setWakeMicrostamp(usecTimestampNow());
|
||||
}
|
||||
|
||||
currentBufferPos = broadcastPacket + 2;
|
||||
currentBufferPos = broadcastPacket + 1;
|
||||
startPointer = currentBufferPos;
|
||||
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
|
@ -146,8 +143,18 @@ int main(int argc, const char * argv[])
|
|||
}
|
||||
}
|
||||
} else {
|
||||
double timeNow = usecTimestampNow();
|
||||
|
||||
// this is the agent, just update last receive to now
|
||||
agent->setLastHeardMicrostamp(usecTimestampNow());
|
||||
agent->setLastHeardMicrostamp(timeNow);
|
||||
|
||||
// grab the ID for this agent so we can send it back with the packet
|
||||
packetAgentID = agent->getAgentId();
|
||||
|
||||
if (packetData[0] == PACKET_HEADER_DOMAIN_RFD
|
||||
&& memchr(SOLO_AGENT_TYPES, agentType, sizeof(SOLO_AGENT_TYPES))) {
|
||||
agent->setWakeMicrostamp(timeNow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,11 +165,13 @@ int main(int argc, const char * argv[])
|
|||
currentBufferPos = addAgentToBroadcastPacket(currentBufferPos, soloAgent->second);
|
||||
}
|
||||
|
||||
if ((packetBytesWithoutLeadingChar = (currentBufferPos - startPointer))) {
|
||||
agentList->getAgentSocket().send((sockaddr*) &agentPublicAddress,
|
||||
broadcastPacket,
|
||||
packetBytesWithoutLeadingChar + 1);
|
||||
}
|
||||
// add the agent ID to the end of the pointer
|
||||
currentBufferPos += packAgentId(currentBufferPos, packetAgentID);
|
||||
|
||||
// send the constructed list back to this agent
|
||||
agentList->getAgentSocket().send((sockaddr*) &agentPublicAddress,
|
||||
broadcastPacket,
|
||||
(currentBufferPos - startPointer) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@ const int MIN_ITERATIONS_BETWEEN_AUDIO_SENDS = (MIN_AUDIO_SEND_INTERVAL_SECS * 1
|
|||
const int MAX_AUDIO_SEND_INTERVAL_SECS = 15;
|
||||
const float MAX_ITERATIONS_BETWEEN_AUDIO_SENDS = (MAX_AUDIO_SEND_INTERVAL_SECS * 1000) / DATA_SEND_INTERVAL_MSECS;
|
||||
|
||||
const int ITERATIONS_BEFORE_HAND_GRAB = 100;
|
||||
const int HAND_GRAB_DURATION_ITERATIONS = 50;
|
||||
const int HAND_TIMER_SLEEP_ITERATIONS = 50;
|
||||
|
||||
bool stopReceiveAgentDataThread;
|
||||
bool injectAudioThreadRunning = false;
|
||||
|
||||
|
@ -130,8 +134,6 @@ int main(int argc, const char* argv[]) {
|
|||
unsigned char broadcastPacket[MAX_PACKET_SIZE];
|
||||
broadcastPacket[0] = PACKET_HEADER_HEAD_DATA;
|
||||
|
||||
int numBytesToSend = 0;
|
||||
|
||||
timeval thisSend;
|
||||
double numMicrosecondsSleep = 0;
|
||||
|
||||
|
@ -145,16 +147,19 @@ int main(int argc, const char* argv[]) {
|
|||
gettimeofday(&thisSend, NULL);
|
||||
|
||||
// find the current avatar mixer
|
||||
Agent *avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
|
||||
Agent* avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
|
||||
|
||||
// make sure we actually have an avatar mixer with an active socket
|
||||
if (avatarMixer != NULL && avatarMixer->getActiveSocket() != NULL) {
|
||||
if (agentList->getOwnerID() != UNKNOWN_AGENT_ID && avatarMixer && avatarMixer->getActiveSocket() != NULL) {
|
||||
unsigned char* packetPosition = broadcastPacket + sizeof(PACKET_HEADER);
|
||||
packetPosition += packAgentId(packetPosition, agentList->getOwnerID());
|
||||
|
||||
// use the getBroadcastData method in the AvatarData class to populate the broadcastPacket buffer
|
||||
numBytesToSend = eve.getBroadcastData((broadcastPacket + 1));
|
||||
packetPosition += eve.getBroadcastData(packetPosition);
|
||||
|
||||
// use the UDPSocket instance attached to our agent list to send avatar data to mixer
|
||||
agentList->getAgentSocket().send(avatarMixer->getActiveSocket(), broadcastPacket, numBytesToSend);
|
||||
}
|
||||
agentList->getAgentSocket().send(avatarMixer->getActiveSocket(), broadcastPacket, packetPosition - broadcastPacket);
|
||||
}
|
||||
|
||||
// temporarily disable Eve's audio sending until the file is actually available on EC2 box
|
||||
if (numIterationsLeftBeforeAudioSend == 0) {
|
||||
|
@ -175,13 +180,12 @@ int main(int argc, const char* argv[]) {
|
|||
|
||||
// simulate the effect of pressing and un-pressing the mouse button/pad
|
||||
handStateTimer++;
|
||||
if ( handStateTimer == 100 ) {
|
||||
|
||||
if (handStateTimer == ITERATIONS_BEFORE_HAND_GRAB) {
|
||||
eve.setHandState(1);
|
||||
}
|
||||
if ( handStateTimer == 150 ) {
|
||||
} else if (handStateTimer == ITERATIONS_BEFORE_HAND_GRAB + HAND_GRAB_DURATION_ITERATIONS) {
|
||||
eve.setHandState(0);
|
||||
}
|
||||
if ( handStateTimer >= 200 ) {
|
||||
} else if (handStateTimer >= ITERATIONS_BEFORE_HAND_GRAB + HAND_GRAB_DURATION_ITERATIONS + HAND_TIMER_SLEEP_ITERATIONS) {
|
||||
handStateTimer = 0;
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 8.4 KiB |
Before Width: | Height: | Size: 15 KiB |
|
@ -34,10 +34,6 @@ const float BODY_ROLL_WHILE_TURNING = 0.1;
|
|||
const float LIN_VEL_DECAY = 5.0;
|
||||
const float MY_HAND_HOLDING_PULL = 0.2;
|
||||
const float YOUR_HAND_HOLDING_PULL = 1.0;
|
||||
|
||||
//const float BODY_SPRING_DEFAULT_TIGHTNESS = 20.0f;
|
||||
//const float BODY_SPRING_FORCE = 6.0f;
|
||||
|
||||
const float BODY_SPRING_DEFAULT_TIGHTNESS = 1500.0f;
|
||||
const float BODY_SPRING_FORCE = 300.0f;
|
||||
|
||||
|
@ -66,8 +62,8 @@ bool usingBigSphereCollisionTest = true;
|
|||
|
||||
char iris_texture_file[] = "resources/images/green_eye.png";
|
||||
|
||||
float chatMessageScale = 0.001;
|
||||
float chatMessageHeight = 0.4;
|
||||
float chatMessageScale = 0.0015;
|
||||
float chatMessageHeight = 0.45;
|
||||
|
||||
vector<unsigned char> iris_texture;
|
||||
unsigned int iris_texture_width = 512;
|
||||
|
@ -144,13 +140,14 @@ Avatar::Avatar(bool isMine) {
|
|||
_renderYaw = 0.0;
|
||||
_renderPitch = 0.0;
|
||||
_sphere = NULL;
|
||||
_interactingOther = NULL;
|
||||
_handHoldingPosition = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
_distanceToNearestAvatar = std::numeric_limits<float>::max();
|
||||
_gravity = glm::vec3(0.0f, -1.0f, 0.0f); // default
|
||||
|
||||
initializeSkeleton();
|
||||
|
||||
_avatarTouch.setReachableRadius(0.6);
|
||||
|
||||
if (iris_texture.size() == 0) {
|
||||
switchToResourcesParentIfRequired();
|
||||
unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file);
|
||||
|
@ -295,7 +292,6 @@ void Avatar::UpdateGyros(float frametime, SerialInterface* serialInterface, glm:
|
|||
if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) {
|
||||
addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
float Avatar::getAbsoluteHeadYaw() const {
|
||||
|
@ -316,16 +312,14 @@ void Avatar::setLeanSideways(float dist){
|
|||
_head.leanSideways = dist;
|
||||
}
|
||||
|
||||
void Avatar::setMousePressed(bool d) {
|
||||
_mousePressed = d;
|
||||
void Avatar::setMousePressed(bool mousePressed) {
|
||||
_mousePressed = mousePressed;
|
||||
}
|
||||
|
||||
|
||||
bool Avatar::getIsNearInteractingOther() {
|
||||
return _avatarTouch.getAbleToReachOtherAvatar();
|
||||
}
|
||||
|
||||
|
||||
void Avatar::simulate(float deltaTime) {
|
||||
|
||||
|
||||
|
@ -335,9 +329,15 @@ void Avatar::simulate(float deltaTime) {
|
|||
// update avatar skeleton
|
||||
updateSkeleton();
|
||||
|
||||
//detect and respond to collisions with other avatars...
|
||||
if (_isMine) {
|
||||
updateAvatarCollisions(deltaTime);
|
||||
}
|
||||
|
||||
//update the movement of the hand and process handshaking with other avatars...
|
||||
updateHandMovementAndTouching(deltaTime);
|
||||
|
||||
|
||||
_avatarTouch.simulate(deltaTime);
|
||||
|
||||
// apply gravity and collision with the ground/floor
|
||||
if (USING_AVATAR_GRAVITY) {
|
||||
|
@ -381,7 +381,7 @@ void Avatar::simulate(float deltaTime) {
|
|||
|
||||
// decay body rotation momentum
|
||||
float bodySpinMomentum = 1.0 - BODY_SPIN_FRICTION * deltaTime;
|
||||
if ( bodySpinMomentum < 0.0f ) { bodySpinMomentum = 0.0f; }
|
||||
if (bodySpinMomentum < 0.0f) { bodySpinMomentum = 0.0f; }
|
||||
_bodyPitchDelta *= bodySpinMomentum;
|
||||
_bodyYawDelta *= bodySpinMomentum;
|
||||
_bodyRollDelta *= bodySpinMomentum;
|
||||
|
@ -430,8 +430,6 @@ void Avatar::simulate(float deltaTime) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
//update the movement of the hand and process handshaking with other avatars...
|
||||
void Avatar::updateHandMovementAndTouching(float deltaTime) {
|
||||
|
||||
// reset hand and arm positions according to hand movement
|
||||
|
@ -441,104 +439,68 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) {
|
|||
+ _orientation.getFront() * -_movedHandOffset.y * 1.0f;
|
||||
|
||||
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += transformedHandMovement;
|
||||
|
||||
if (_isMine) {
|
||||
_handState = _mousePressed;
|
||||
}
|
||||
|
||||
//reset these for the next go-round
|
||||
_avatarTouch.setAbleToReachOtherAvatar (false);
|
||||
_avatarTouch.setHandsCloseEnoughToGrasp(false);
|
||||
|
||||
// if the avatar being simulated is mine, then loop through
|
||||
// all the other avatars for potential interactions...
|
||||
|
||||
if (_isMine)
|
||||
{
|
||||
// Reset detector for nearest avatar
|
||||
_distanceToNearestAvatar = std::numeric_limits<float>::max();
|
||||
_avatarTouch.setMyBodyPosition(_position);
|
||||
|
||||
Avatar * _interactingOther = NULL;
|
||||
float closestDistance = std::numeric_limits<float>::max();
|
||||
|
||||
//loop through all the other avatars for potential interactions...
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
Avatar *otherAvatar = (Avatar *)agent->getLinkedData();
|
||||
|
||||
// check for collisions with other avatars and respond
|
||||
updateCollisionWithOtherAvatar(otherAvatar, deltaTime );
|
||||
|
||||
// test other avatar hand position for proximity
|
||||
glm::vec3 v(_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position);
|
||||
v -= otherAvatar->getJointPosition(AVATAR_JOINT_RIGHT_SHOULDER);
|
||||
/*
|
||||
// Test: Show angle between your fwd vector and nearest avatar
|
||||
glm::vec3 vectorBetweenUs = otherAvatar->getJointPosition(AVATAR_JOINT_PELVIS) -
|
||||
getJointPosition(AVATAR_JOINT_PELVIS);
|
||||
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
|
||||
glm::vec3 v(_position - otherAvatar->_position);
|
||||
float distance = glm::length(v);
|
||||
if (distance < _distanceToNearestAvatar) {_distanceToNearestAvatar = distance;}
|
||||
|
||||
if (distance < _maxArmLength + _maxArmLength) {
|
||||
|
||||
if (distance < closestDistance) {
|
||||
closestDistance = distance;
|
||||
_interactingOther = otherAvatar;
|
||||
|
||||
if (! _avatarTouch.getAbleToReachOtherAvatar()) {
|
||||
//initialize _handHolding
|
||||
_handHoldingPosition = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position;
|
||||
_avatarTouch.setAbleToReachOtherAvatar(true);
|
||||
}
|
||||
|
||||
glm::vec3 vectorBetweenHands(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
|
||||
vectorBetweenHands -= otherAvatar->getJointPosition(AVATAR_JOINT_RIGHT_FINGERTIPS);
|
||||
float distanceBetweenHands = glm::length(vectorBetweenHands);
|
||||
|
||||
if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP) {
|
||||
_avatarTouch.setHandsCloseEnoughToGrasp(true);
|
||||
}
|
||||
|
||||
// if I am holding hands with another avatar, a force is applied
|
||||
if ((_handState == 1) || (_interactingOther->_handState == 1)) {
|
||||
|
||||
// if the hands are close enough to grasp...
|
||||
if (distanceBetweenHands < HANDS_CLOSE_ENOUGH_TO_GRASP)
|
||||
{
|
||||
// apply the forces...
|
||||
glm::vec3 vectorToOtherHand = _interactingOther->_handPosition - _handHoldingPosition;
|
||||
glm::vec3 vectorToMyHand = _joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position - _handHoldingPosition;
|
||||
|
||||
_handHoldingPosition += vectorToOtherHand * YOUR_HAND_HOLDING_PULL;
|
||||
_handHoldingPosition += vectorToMyHand * MY_HAND_HOLDING_PULL;
|
||||
_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handHoldingPosition;
|
||||
|
||||
// apply a force to the avatar body
|
||||
if (glm::length(vectorToOtherHand) > _maxArmLength * 0.9) {
|
||||
_velocity += vectorToOtherHand;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the vector we send for hand position to other people to be our right hand
|
||||
setHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
|
||||
|
||||
if (_interactingOther) {
|
||||
_avatarTouch.setYourBodyPosition(_interactingOther->_position);
|
||||
_avatarTouch.setYourHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition);
|
||||
_avatarTouch.setYourHandState (_interactingOther->_handState);
|
||||
}
|
||||
|
||||
}//if (_isMine)
|
||||
|
||||
//constrain right arm length and re-adjust elbow position as it bends
|
||||
// NOTE - the following must be called on all avatars - not just _isMine
|
||||
updateArmIKAndConstraints(deltaTime);
|
||||
|
||||
// set hand positions for _avatarTouch.setMyHandPosition AFTER calling updateArmIKAndConstraints
|
||||
if (_interactingOther) {
|
||||
if (_isMine) {
|
||||
_avatarTouch.setMyHandPosition (_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
|
||||
_avatarTouch.setYourHandPosition(_interactingOther->_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
|
||||
_avatarTouch.setMyHandState (_handState);
|
||||
_avatarTouch.setYourHandState (_interactingOther->_handState);
|
||||
_avatarTouch.simulate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_avatarTouch.getAbleToReachOtherAvatar() ) {
|
||||
_interactingOther = NULL;
|
||||
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);
|
||||
|
||||
if (_mousePressed) {
|
||||
_handState = 1;
|
||||
} else {
|
||||
_handState = 0;
|
||||
}
|
||||
|
||||
_avatarTouch.setMyHandState(_handState);
|
||||
|
||||
if (_handState == 1) {
|
||||
_avatarTouch.setMyHandPosition(_joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].springyPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Avatar::updateHead(float deltaTime) {
|
||||
|
||||
//apply the head lean values to the springy position...
|
||||
|
@ -690,66 +652,96 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d
|
|||
}
|
||||
|
||||
|
||||
//detect collisions with other avatars and respond
|
||||
void Avatar::updateCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) {
|
||||
|
||||
// check if the bounding spheres of the two avatars are colliding
|
||||
glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position);
|
||||
if (glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF) {
|
||||
|
||||
void Avatar::updateAvatarCollisions(float deltaTime) {
|
||||
|
||||
// Reset detector for nearest avatar
|
||||
_distanceToNearestAvatar = std::numeric_limits<float>::max();
|
||||
|
||||
//loop through all the other avatars for potential interactions...
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
Avatar *otherAvatar = (Avatar *)agent->getLinkedData();
|
||||
|
||||
// check if the bounding spheres of the two avatars are colliding
|
||||
glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position);
|
||||
if (glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF) {
|
||||
//apply forces from collision
|
||||
applyCollisionWithOtherAvatar(otherAvatar, deltaTime );
|
||||
}
|
||||
|
||||
// test other avatar hand position for proximity
|
||||
glm::vec3 v(_joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position);
|
||||
v -= otherAvatar->getPosition();
|
||||
|
||||
float distance = glm::length(v);
|
||||
if (distance < _distanceToNearestAvatar) {
|
||||
_distanceToNearestAvatar = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//detect collisions with other avatars and respond
|
||||
void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) {
|
||||
|
||||
float bodyMomentum = 1.0f;
|
||||
glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// loop through the joints of each avatar to check for every possible collision
|
||||
for (int b=1; b<NUM_AVATAR_JOINTS; b++) {
|
||||
if (_joint[b].isCollidable) {
|
||||
// loop through the joints of each avatar to check for every possible collision
|
||||
for (int b=1; b<NUM_AVATAR_JOINTS; b++) {
|
||||
if (_joint[b].isCollidable) {
|
||||
|
||||
for (int o=b+1; o<NUM_AVATAR_JOINTS; o++) {
|
||||
if (otherAvatar->_joint[o].isCollidable) {
|
||||
for (int o=b+1; o<NUM_AVATAR_JOINTS; o++) {
|
||||
if (otherAvatar->_joint[o].isCollidable) {
|
||||
|
||||
glm::vec3 vectorBetweenJoints(_joint[b].springyPosition - otherAvatar->_joint[o].springyPosition);
|
||||
float distanceBetweenJoints = glm::length(vectorBetweenJoints);
|
||||
|
||||
glm::vec3 vectorBetweenJoints(_joint[b].springyPosition - otherAvatar->_joint[o].springyPosition);
|
||||
float distanceBetweenJoints = glm::length(vectorBetweenJoints);
|
||||
|
||||
if (distanceBetweenJoints > 0.0 ) { // to avoid divide by zero
|
||||
float combinedRadius = _joint[b].radius + otherAvatar->_joint[o].radius;
|
||||
if (distanceBetweenJoints > 0.0 ) { // to avoid divide by zero
|
||||
float combinedRadius = _joint[b].radius + otherAvatar->_joint[o].radius;
|
||||
|
||||
// check for collision
|
||||
if (distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) {
|
||||
glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints;
|
||||
// check for collision
|
||||
if (distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) {
|
||||
glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints;
|
||||
|
||||
// push balls away from each other and apply friction
|
||||
glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime;
|
||||
|
||||
float ballMomentum = 1.0 - COLLISION_BALL_FRICTION * deltaTime;
|
||||
if (ballMomentum < 0.0 ) { ballMomentum = 0.0;}
|
||||
|
||||
_joint[b].springyVelocity += ballPushForce;
|
||||
otherAvatar->_joint[o].springyVelocity -= ballPushForce;
|
||||
|
||||
_joint[b].springyVelocity *= ballMomentum;
|
||||
otherAvatar->_joint[o].springyVelocity *= ballMomentum;
|
||||
|
||||
// accumulate forces and frictions to apply to the velocities of avatar bodies
|
||||
bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime;
|
||||
bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime;
|
||||
if (bodyMomentum < 0.0 ) { bodyMomentum = 0.0;}
|
||||
|
||||
}// check for collision
|
||||
} // to avoid divide by zero
|
||||
} // o loop
|
||||
} // collidable
|
||||
} // b loop
|
||||
} // collidable
|
||||
|
||||
|
||||
//apply forces and frictions on the bodies of both avatars
|
||||
_velocity += bodyPushForce;
|
||||
otherAvatar->_velocity -= bodyPushForce;
|
||||
_velocity *= bodyMomentum;
|
||||
otherAvatar->_velocity *= bodyMomentum;
|
||||
}
|
||||
|
||||
// push balls away from each other and apply friction
|
||||
glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * deltaTime;
|
||||
|
||||
float ballMomentum = 1.0 - COLLISION_BALL_FRICTION * deltaTime;
|
||||
if (ballMomentum < 0.0 ) { ballMomentum = 0.0;}
|
||||
|
||||
_joint[b].springyVelocity += ballPushForce;
|
||||
otherAvatar->_joint[o].springyVelocity -= ballPushForce;
|
||||
|
||||
_joint[b].springyVelocity *= ballMomentum;
|
||||
otherAvatar->_joint[o].springyVelocity *= ballMomentum;
|
||||
|
||||
// accumulate forces and frictions to apply to the velocities of avatar bodies
|
||||
bodyPushForce += directionVector * COLLISION_BODY_FORCE * deltaTime;
|
||||
bodyMomentum -= COLLISION_BODY_FRICTION * deltaTime;
|
||||
if (bodyMomentum < 0.0 ) { bodyMomentum = 0.0;}
|
||||
|
||||
}// check for collision
|
||||
} // to avoid divide by zero
|
||||
} // o loop
|
||||
} // collidable
|
||||
} // b loop
|
||||
} // collidable
|
||||
|
||||
|
||||
//apply forces and frictions on the bodies of both avatars
|
||||
_velocity += bodyPushForce;
|
||||
otherAvatar->_velocity -= bodyPushForce;
|
||||
_velocity *= bodyMomentum;
|
||||
otherAvatar->_velocity *= bodyMomentum;
|
||||
|
||||
} // bounding sphere collision
|
||||
} //method
|
||||
|
||||
|
||||
void Avatar::setDisplayingHead(bool displayingHead ) {
|
||||
|
@ -768,7 +760,7 @@ void Avatar::setGravity(glm::vec3 gravity) {
|
|||
}
|
||||
|
||||
|
||||
void Avatar::render(bool lookingInMirror) {
|
||||
void Avatar::render(bool lookingInMirror, glm::vec3 cameraPosition) {
|
||||
|
||||
// render a simple round on the ground projected down from the avatar's position
|
||||
renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f ), 0.1f, 0.2f );
|
||||
|
@ -803,7 +795,7 @@ void Avatar::render(bool lookingInMirror) {
|
|||
|
||||
// if this is my avatar, then render my interactions with the other avatar
|
||||
if (_isMine ) {
|
||||
_avatarTouch.render();
|
||||
_avatarTouch.render(cameraPosition);
|
||||
}
|
||||
|
||||
// Render the balls
|
||||
|
@ -1193,6 +1185,9 @@ void Avatar::initializeSkeleton() {
|
|||
|
||||
// generate world positions
|
||||
updateSkeleton();
|
||||
|
||||
//set spring positions to be in the skeleton bone positions
|
||||
initializeBodySprings();
|
||||
}
|
||||
|
||||
void Avatar::calculateBoneLengths() {
|
||||
|
|
|
@ -101,13 +101,6 @@ public:
|
|||
void setLeanForward(float dist);
|
||||
void setLeanSideways(float dist);
|
||||
void addLean(float x, float z);
|
||||
|
||||
/*
|
||||
const glm::vec3& getHeadRightDirection() const { return _orientation.getRight(); };
|
||||
const glm::vec3& getHeadUpDirection () const { return _orientation.getUp (); };
|
||||
const glm::vec3& getHeadFrontDirection() const { return _orientation.getFront(); };
|
||||
*/
|
||||
|
||||
const glm::vec3& getHeadPosition() const ;
|
||||
const glm::vec3& getJointPosition(AvatarJointID j) const { return _joint[j].position; };
|
||||
const glm::vec3& getBodyUpDirection() const { return _orientation.getUp(); };
|
||||
|
@ -117,8 +110,8 @@ public:
|
|||
|
||||
AvatarMode getMode();
|
||||
|
||||
void setMousePressed( bool pressed );
|
||||
void render(bool lookingInMirror);
|
||||
void setMousePressed(bool pressed);
|
||||
void render(bool lookingInMirrorm, glm::vec3 cameraPosition);
|
||||
void renderBody();
|
||||
void renderHead(bool lookingInMirror);
|
||||
void simulate(float);
|
||||
|
@ -241,7 +234,6 @@ private:
|
|||
float _transmitterHz;
|
||||
int _transmitterPackets;
|
||||
glm::vec3 _transmitterInitialReading;
|
||||
Avatar* _interactingOther;
|
||||
float _pelvisStandingHeight;
|
||||
float _height;
|
||||
Balls* _balls;
|
||||
|
@ -260,8 +252,9 @@ private:
|
|||
void readSensors();
|
||||
void updateHead( float deltaTime );
|
||||
void updateHandMovementAndTouching(float deltaTime);
|
||||
void updateAvatarCollisions(float deltaTime);
|
||||
void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime );
|
||||
void updateCollisionWithOtherAvatar( Avatar * other, float deltaTime );
|
||||
void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime );
|
||||
void setHeadFromGyros(glm::vec3 * eulerAngles, glm::vec3 * angularVelocity, float deltaTime, float smoothingTime);
|
||||
void setHeadSpringScale(float s) { _head.returnSpringScale = s; }
|
||||
};
|
||||
|
|
|
@ -16,13 +16,4 @@ AvatarRenderer::AvatarRenderer() {
|
|||
|
||||
// this method renders the avatar
|
||||
void AvatarRenderer::render(Avatar *avatar, bool lookingInMirror) {
|
||||
/*
|
||||
// show avatar position
|
||||
glColor4f( 0.5f, 0.5f, 0.5f, 0.6 );
|
||||
glPushMatrix();
|
||||
glTranslatef(avatar->_position.x, avatar->_position.y, avatar->_position.z);
|
||||
glScalef( 0.03, 0.03, 0.03 );
|
||||
glutSolidSphere( 1, 10, 10 );
|
||||
glPopMatrix();
|
||||
*/
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
#include <SharedUtil.h>
|
||||
#include "AvatarTouch.h"
|
||||
#include "InterfaceConfig.h"
|
||||
#include "Util.h"
|
||||
|
||||
const float THREAD_RADIUS = 0.012;
|
||||
|
||||
|
@ -17,8 +18,11 @@ AvatarTouch::AvatarTouch() {
|
|||
|
||||
_myHandPosition = 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 );
|
||||
_yourBodyPosition = glm::vec3( 0.0f, 0.0f, 0.0f );
|
||||
_myHandState = 0;
|
||||
_yourHandState = 0;
|
||||
_yourHandState = 0;
|
||||
_reachableRadius = 0.0f;
|
||||
|
||||
_canReachToOtherAvatar = false;
|
||||
_handsCloseEnoughToGrasp = false;
|
||||
|
@ -28,40 +32,46 @@ AvatarTouch::AvatarTouch() {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarTouch::setMyHandPosition( glm::vec3 position ) {
|
||||
void AvatarTouch::setMyHandPosition(glm::vec3 position) {
|
||||
_myHandPosition = position;
|
||||
}
|
||||
|
||||
void AvatarTouch::setYourHandPosition( glm::vec3 position ) {
|
||||
void AvatarTouch::setYourHandPosition(glm::vec3 position) {
|
||||
_yourHandPosition = position;
|
||||
}
|
||||
|
||||
void AvatarTouch::setMyHandState( int state ) {
|
||||
void AvatarTouch::setMyBodyPosition(glm::vec3 position) {
|
||||
_myBodyPosition = position;
|
||||
}
|
||||
|
||||
void AvatarTouch::setYourBodyPosition(glm::vec3 position) {
|
||||
_yourBodyPosition = position;
|
||||
}
|
||||
|
||||
void AvatarTouch::setMyHandState(int state) {
|
||||
_myHandState = state;
|
||||
}
|
||||
|
||||
void AvatarTouch::setYourHandState( int state ) {
|
||||
void AvatarTouch::setYourHandState(int state) {
|
||||
_yourHandState = state;
|
||||
}
|
||||
|
||||
void AvatarTouch::render() {
|
||||
void AvatarTouch::setReachableRadius(float r) {
|
||||
_reachableRadius = r;
|
||||
}
|
||||
|
||||
glm::vec3 v1( _myHandPosition );
|
||||
glm::vec3 v2( _yourHandPosition );
|
||||
|
||||
void AvatarTouch::render(glm::vec3 cameraPosition) {
|
||||
|
||||
if (_canReachToOtherAvatar) {
|
||||
// if my hand is grasping, show it...
|
||||
if ( _myHandState == 1 ) {
|
||||
glPushMatrix();
|
||||
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.4, 0.2 ); glutSolidSphere( 0.025f, 10.0f, 10.0f );
|
||||
glColor4f( 1.0, 1.0, 0.2, 0.1 ); glutSolidSphere( 0.030f, 10.0f, 10.0f );
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
glColor4f( 0.3, 0.4, 0.5, 0.5 );
|
||||
glm::vec3 p(_yourBodyPosition);
|
||||
p.y = 0.0005f;
|
||||
renderCircle(p, _reachableRadius, glm::vec3(0.0f, 1.0f, 0.0f), 30);
|
||||
|
||||
// if your hand is grasping, show it...
|
||||
if ( _yourHandState == 1 ) {
|
||||
if (_yourHandState == 1) {
|
||||
glPushMatrix();
|
||||
glTranslatef(_yourHandPosition.x, _yourHandPosition.y, _yourHandPosition.z);
|
||||
glColor4f( 1.0, 1.0, 0.8, 0.3 ); glutSolidSphere( 0.020f, 10.0f, 10.0f );
|
||||
|
@ -69,35 +79,61 @@ void AvatarTouch::render() {
|
|||
glColor4f( 1.0, 1.0, 0.2, 0.1 ); glutSolidSphere( 0.030f, 10.0f, 10.0f );
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//show beam
|
||||
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 (_myHandState == 1) {
|
||||
glPushMatrix();
|
||||
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.4, 0.2 ); glutSolidSphere( 0.025f, 10.0f, 10.0f );
|
||||
glColor4f( 1.0, 1.0, 0.2, 0.1 ); glutSolidSphere( 0.030f, 10.0f, 10.0f );
|
||||
glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AvatarTouch::simulate (float deltaTime) {
|
||||
|
||||
glm::vec3 v = _yourHandPosition - _myHandPosition;
|
||||
glm::vec3 v = _yourBodyPosition - _myBodyPosition;
|
||||
|
||||
float distance = glm::length(v);
|
||||
|
||||
if (distance < _reachableRadius ) {
|
||||
_canReachToOtherAvatar = true;
|
||||
} else {
|
||||
_canReachToOtherAvatar = false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
for (int p=0; p<NUM_POINTS; p++) {
|
||||
_point[p] = _myHandPosition + v * ( (float)p / (float)NUM_POINTS );
|
||||
_point[p].x += randFloatInRange( -THREAD_RADIUS, THREAD_RADIUS );
|
||||
_point[p].y += randFloatInRange( -THREAD_RADIUS, THREAD_RADIUS );
|
||||
_point[p].z += randFloatInRange( -THREAD_RADIUS, THREAD_RADIUS );
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
|
@ -19,30 +19,35 @@ public:
|
|||
AvatarTouch();
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
void render(glm::vec3 cameraPosition);
|
||||
|
||||
void setMyHandPosition ( glm::vec3 position );
|
||||
void setYourHandPosition( glm::vec3 position );
|
||||
void setMyHandState ( int state );
|
||||
void setYourHandState ( int state );
|
||||
void setMyHandPosition (glm::vec3 position);
|
||||
void setYourHandPosition(glm::vec3 position);
|
||||
void setMyBodyPosition (glm::vec3 position);
|
||||
void setYourBodyPosition(glm::vec3 position);
|
||||
void setMyHandState (int state);
|
||||
void setYourHandState (int state);
|
||||
void setReachableRadius (float r);
|
||||
void setAbleToReachOtherAvatar (bool a) {_canReachToOtherAvatar = a;}
|
||||
void setHandsCloseEnoughToGrasp(bool h) {_handsCloseEnoughToGrasp = h;}
|
||||
|
||||
void setAbleToReachOtherAvatar ( bool a ) { _canReachToOtherAvatar = a; }
|
||||
void setHandsCloseEnoughToGrasp( bool h ) { _handsCloseEnoughToGrasp = h; }
|
||||
|
||||
bool getAbleToReachOtherAvatar () { return _canReachToOtherAvatar; }
|
||||
bool getHandsCloseEnoughToGrasp() { return _handsCloseEnoughToGrasp; }
|
||||
bool getAbleToReachOtherAvatar () const {return _canReachToOtherAvatar;}
|
||||
bool getHandsCloseEnoughToGrasp() const {return _handsCloseEnoughToGrasp;}
|
||||
|
||||
private:
|
||||
|
||||
static const int NUM_POINTS = 100;
|
||||
|
||||
glm::vec3 _point [NUM_POINTS];
|
||||
glm::vec3 _myBodyPosition;
|
||||
glm::vec3 _yourBodyPosition;
|
||||
glm::vec3 _myHandPosition;
|
||||
glm::vec3 _yourHandPosition;
|
||||
int _myHandState;
|
||||
int _yourHandState;
|
||||
bool _canReachToOtherAvatar;
|
||||
bool _handsCloseEnoughToGrasp;
|
||||
float _reachableRadius;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -150,30 +150,63 @@ void SerialInterface::renderLevels(int width, int height) {
|
|||
int i;
|
||||
int disp_x = 10;
|
||||
const int GAP = 16;
|
||||
char val[10];
|
||||
for(i = 0; i < NUM_CHANNELS; i++) {
|
||||
// Actual value
|
||||
char val[40];
|
||||
if (!USING_INVENSENSE_MPU9150) {
|
||||
for(i = 0; i < NUM_CHANNELS; i++) {
|
||||
// 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_Y = 200;
|
||||
|
||||
// Draw the text values
|
||||
sprintf(val, "Yaw %d", _lastYaw);
|
||||
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y, 0.10, 0, 1.0, 1, val, 0, 1, 0);
|
||||
sprintf(val, "Pitch %d", _lastPitch);
|
||||
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 15, 0.10, 0, 1.0, 1, val, 0, 1, 0);
|
||||
sprintf(val, "Roll %d", _lastRoll);
|
||||
drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 30, 0.10, 0, 1.0, 1, val, 0, 1, 0);
|
||||
|
||||
// Draw the levels as horizontal lines
|
||||
const int LEVEL_CENTER = 150;
|
||||
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));
|
||||
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 3);
|
||||
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastYaw, LEVEL_CORNER_Y - 3);
|
||||
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 12);
|
||||
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastPitch, LEVEL_CORNER_Y + 12);
|
||||
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 27);
|
||||
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _lastRoll, LEVEL_CORNER_Y + 27);
|
||||
glEnd();
|
||||
// Trailing Average value
|
||||
// Draw green vertical centerline
|
||||
glColor4f(0, 1, 0, 0.5);
|
||||
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));
|
||||
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 6);
|
||||
glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 30);
|
||||
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;
|
||||
}
|
||||
|
||||
// Display Serial latency block
|
||||
if (LED) {
|
||||
glColor3f(1,0,0);
|
||||
|
@ -204,7 +237,7 @@ void SerialInterface::readData() {
|
|||
|
||||
int initialSamples = totalSamples;
|
||||
|
||||
if (USING_INVENSENSE_MPU9150) {
|
||||
if (USING_INVENSENSE_MPU9150) {
|
||||
unsigned char gyroBuffer[20];
|
||||
|
||||
// ask the invensense for raw gyro data
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
//
|
||||
// Texture.cpp
|
||||
// interface
|
||||
//
|
||||
// Added by Yoz on 11/5/12.
|
||||
//
|
||||
// Code lifted from http://en.wikibooks.org/wiki/OpenGL_Programming/Intermediate/Textures
|
||||
|
||||
#include "Texture.h"
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <lodepng.h>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
|
||||
#define TEXTURE_LOAD_ERROR 0
|
||||
|
||||
/**
|
||||
* Read a given filename as a PNG texture, and set
|
||||
it as the current default OpenGL texture.
|
||||
* @param[in] filename Relative path to PNG file
|
||||
* @return Zero for success.
|
||||
*/
|
||||
|
||||
int load_png_as_texture(char* filename)
|
||||
{
|
||||
std::vector<unsigned char> image;
|
||||
// width and height will be read from the file at the start
|
||||
// and loaded into these vars
|
||||
unsigned int width = 1, height = 1;
|
||||
unsigned error = lodepng::decode(image, width, height, filename);
|
||||
if (error) {
|
||||
printLog("Error loading texture\n");
|
||||
return (int) error;
|
||||
}
|
||||
|
||||
// Make some OpenGL properties better for 2D and enable alpha channel.
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
|
||||
if(glGetError() != GL_NO_ERROR)
|
||||
{
|
||||
printLog("Error initing GL\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Texture size must be power of two for the primitive OpenGL version this is written for. Find next power of two.
|
||||
size_t u2 = 1; while(u2 < width) u2 *= 2;
|
||||
size_t v2 = 1; while(v2 < height) v2 *= 2;
|
||||
// Ratio for power of two version compared to actual version, to render the non power of two image with proper size.
|
||||
// double u3 = (double)width / u2;
|
||||
// double v3 = (double)height / v2;
|
||||
|
||||
// Make power of two version of the image.
|
||||
std::vector<unsigned char> image2(u2 * v2 * 4);
|
||||
for(size_t y = 0; y < height; y++)
|
||||
for(size_t x = 0; x < width; x++)
|
||||
for(size_t c = 0; c < 4; c++)
|
||||
{
|
||||
image2[4 * u2 * y + 4 * x + c] = image[4 * width * y + 4 * x + c];
|
||||
}
|
||||
|
||||
// Enable the texture for OpenGL.
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); //GL_NEAREST = no smoothing
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, 4, u2, v2, 0, GL_RGBA, GL_UNSIGNED_BYTE, &image2[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
//
|
||||
// Texture.h
|
||||
// interface
|
||||
//
|
||||
// Created by Yoz Work on 11/5/12.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __interface__Texture__
|
||||
#define __interface__Texture__
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
int load_png_as_texture(char* filename);
|
||||
|
||||
#endif /* defined(__interface__texture__) */
|
|
@ -11,6 +11,7 @@
|
|||
#include <cstring>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/noise.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
|
@ -65,81 +66,107 @@ float angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float
|
|||
return atan2(head_pos.x - source_pos.x, head_pos.z - source_pos.z) * 180.0f / PIf + render_yaw + head_yaw;
|
||||
}
|
||||
|
||||
void render_vector(glm::vec3 * vec)
|
||||
{
|
||||
// Show edge of world
|
||||
glDisable(GL_LIGHTING);
|
||||
glColor4f(1.0, 1.0, 1.0, 1.0);
|
||||
glLineWidth(1.0);
|
||||
glBegin(GL_LINES);
|
||||
// Draw axes
|
||||
glColor3f(1,0,0);
|
||||
glVertex3f(-1,0,0);
|
||||
glVertex3f(1,0,0);
|
||||
glColor3f(0,1,0);
|
||||
glVertex3f(0,-1,0);
|
||||
glVertex3f(0, 1, 0);
|
||||
glColor3f(0,0,1);
|
||||
glVertex3f(0,0,-1);
|
||||
glVertex3f(0, 0, 1);
|
||||
// Draw vector
|
||||
glColor3f(1,1,1);
|
||||
glVertex3f(0,0,0);
|
||||
glVertex3f(vec->x, vec->y, vec->z);
|
||||
// Draw marker dots for magnitude
|
||||
glEnd();
|
||||
float particleAttenuationQuadratic[] = { 0.0f, 0.0f, 2.0f }; // larger Z = smaller particles
|
||||
float particleAttenuationConstant[] = { 1.0f, 0.0f, 0.0f };
|
||||
|
||||
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particleAttenuationQuadratic );
|
||||
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glPointSize(10.0);
|
||||
glBegin(GL_POINTS);
|
||||
glColor3f(1,0,0);
|
||||
glVertex3f(vec->x,0,0);
|
||||
glColor3f(0,1,0);
|
||||
glVertex3f(0,vec->y,0);
|
||||
glColor3f(0,0,1);
|
||||
glVertex3f(0,0,vec->z);
|
||||
glEnd();
|
||||
|
||||
glPointParameterfvARB( GL_POINT_DISTANCE_ATTENUATION_ARB, particleAttenuationConstant );
|
||||
// Helper function returns the positive angle in degrees between two 3D vectors
|
||||
float angleBetween(glm::vec3 * v1, glm::vec3 * v2) {
|
||||
return acos((glm::dot(*v1, *v2)) / (glm::length(*v1) * glm::length(*v2))) * 180.f / PI;
|
||||
}
|
||||
|
||||
void render_world_box()
|
||||
{
|
||||
// Draw a 3D vector floating in space
|
||||
void drawVector(glm::vec3 * vector) {
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glPointSize(3.0);
|
||||
glLineWidth(2.0);
|
||||
|
||||
// Draw axes
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(1,0,0);
|
||||
glVertex3f(0,0,0);
|
||||
glVertex3f(1,0,0);
|
||||
glColor3f(0,1,0);
|
||||
glVertex3f(0,0,0);
|
||||
glVertex3f(0, 1, 0);
|
||||
glColor3f(0,0,1);
|
||||
glVertex3f(0,0,0);
|
||||
glVertex3f(0, 0, 1);
|
||||
glEnd();
|
||||
|
||||
// Draw the vector itself
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(1,1,1);
|
||||
glVertex3f(0,0,0);
|
||||
glVertex3f(vector->x, vector->y, vector->z);
|
||||
glEnd();
|
||||
|
||||
// Draw spheres for magnitude
|
||||
glPushMatrix();
|
||||
glColor3f(1,0,0);
|
||||
glTranslatef(vector->x, 0, 0);
|
||||
glutSolidSphere(0.02, 10, 10);
|
||||
glColor3f(0,1,0);
|
||||
glTranslatef(-vector->x, vector->y, 0);
|
||||
glutSolidSphere(0.02, 10, 10);
|
||||
glColor3f(0,0,1);
|
||||
glTranslatef(0, -vector->y, vector->z);
|
||||
glutSolidSphere(0.02, 10, 10);
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
|
||||
// Render a 2D set of squares using perlin/fractal noise
|
||||
void noiseTest(int w, int h) {
|
||||
const float CELLS = 100;
|
||||
float xStep = (float) w / CELLS;
|
||||
float yStep = (float) h / CELLS;
|
||||
glBegin(GL_QUADS);
|
||||
for (float x = 0; x < (float)w; x += xStep) {
|
||||
for (float y = 0; y < (float)h; y += yStep) {
|
||||
// Generate a vector varying between 0-1 corresponding to the screen location
|
||||
glm::vec2 position(x / (float) w, y / (float) h);
|
||||
// Set the cell color using the noise value at that location
|
||||
float color = glm::simplex(position);
|
||||
glColor4f(color, color, color, 1.0);
|
||||
glVertex2f(x, y);
|
||||
glVertex2f(x + xStep, y);
|
||||
glVertex2f(x + xStep, y + yStep);
|
||||
glVertex2f(x, y + yStep);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void render_world_box() {
|
||||
// Show edge of world
|
||||
glDisable(GL_LIGHTING);
|
||||
glColor4f(1.0, 1.0, 1.0, 1.0);
|
||||
glLineWidth(1.0);
|
||||
glBegin(GL_LINES);
|
||||
glColor3f(1,0,0);
|
||||
glVertex3f(0,0,0);
|
||||
glVertex3f(WORLD_SIZE,0,0);
|
||||
glColor3f(0,1,0);
|
||||
glVertex3f(0,0,0);
|
||||
glColor3f(1, 0, 0);
|
||||
glVertex3f(0, 0, 0);
|
||||
glVertex3f(WORLD_SIZE, 0, 0);
|
||||
glColor3f(0, 1, 0);
|
||||
glVertex3f(0, 0, 0);
|
||||
glVertex3f(0, WORLD_SIZE, 0);
|
||||
glColor3f(0,0,1);
|
||||
glVertex3f(0,0,0);
|
||||
glColor3f(0, 0, 1);
|
||||
glVertex3f(0, 0, 0);
|
||||
glVertex3f(0, 0, WORLD_SIZE);
|
||||
glEnd();
|
||||
// Draw little marker dots along the axis
|
||||
glEnable(GL_LIGHTING);
|
||||
glPushMatrix();
|
||||
glTranslatef(WORLD_SIZE,0,0);
|
||||
glColor3f(1,0,0);
|
||||
glutSolidSphere(0.125,10,10);
|
||||
glTranslatef(WORLD_SIZE, 0, 0);
|
||||
glColor3f(1, 0, 0);
|
||||
glutSolidSphere(0.125, 10, 10);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glTranslatef(0,WORLD_SIZE,0);
|
||||
glColor3f(0,1,0);
|
||||
glutSolidSphere(0.125,10,10);
|
||||
glTranslatef(0, WORLD_SIZE, 0);
|
||||
glColor3f(0, 1, 0);
|
||||
glutSolidSphere(0.125, 10, 10);
|
||||
glPopMatrix();
|
||||
glPushMatrix();
|
||||
glTranslatef(0,0,WORLD_SIZE);
|
||||
glColor3f(0,0,1);
|
||||
glutSolidSphere(0.125,10,10);
|
||||
glTranslatef(0, 0, WORLD_SIZE);
|
||||
glColor3f(0, 0, 1);
|
||||
glutSolidSphere(0.125, 10, 10);
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
|
@ -166,8 +193,7 @@ float widthChar(float scale, int mono, char ch) {
|
|||
}
|
||||
|
||||
void drawtext(int x, int y, float scale, float rotate, float thick, int mono,
|
||||
char const* string, float r, float g, float b)
|
||||
{
|
||||
char const* string, float r, float g, float b) {
|
||||
//
|
||||
// Draws text on screen as stroked so it can be resized
|
||||
//
|
||||
|
@ -184,10 +210,7 @@ void drawtext(int x, int y, float scale, float rotate, float thick, int mono,
|
|||
|
||||
}
|
||||
|
||||
|
||||
void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, glm::vec3 vec,
|
||||
float r, float g, float b)
|
||||
{
|
||||
void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, glm::vec3 vec, float r, float g, float b) {
|
||||
//
|
||||
// Draws text on screen as stroked so it can be resized
|
||||
//
|
||||
|
@ -202,18 +225,15 @@ void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, gl
|
|||
glLineWidth(thick);
|
||||
glScalef(scale, scale, 1.0);
|
||||
len = (int) strlen(vectext);
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!mono) glutStrokeCharacter(GLUT_STROKE_ROMAN, int(vectext[i]));
|
||||
else glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, int(vectext[i]));
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
}
|
||||
|
||||
void drawGroundPlaneGrid(float size)
|
||||
{
|
||||
|
||||
void drawGroundPlaneGrid(float size) {
|
||||
glColor3f( 0.4f, 0.5f, 0.3f );
|
||||
glLineWidth(2.0);
|
||||
|
||||
|
@ -267,6 +287,51 @@ void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, f
|
|||
}
|
||||
|
||||
|
||||
|
||||
void renderSphereOutline(glm::vec3 position, float radius, int numSides, glm::vec3 cameraPosition) {
|
||||
glm::vec3 vectorToPosition(glm::normalize(position - cameraPosition));
|
||||
glm::vec3 right = glm::cross(vectorToPosition, glm::vec3( 0.0f, 1.0f, 0.0f));
|
||||
glm::vec3 up = glm::cross(right, vectorToPosition);
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
for (int i=0; i<numSides+1; i++) {
|
||||
float r = ((float)i / (float)numSides) * PI * 2.0;
|
||||
float s = radius * sin(r);
|
||||
float c = radius * cos(r);
|
||||
|
||||
glVertex3f
|
||||
(
|
||||
position.x + right.x * s + up.x * c,
|
||||
position.y + right.y * s + up.y * c,
|
||||
position.z + right.z * s + up.z * c
|
||||
);
|
||||
}
|
||||
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
void renderCircle(glm::vec3 position, float radius, glm::vec3 surfaceNormal, int numSides ) {
|
||||
glm::vec3 perp1 = glm::vec3(surfaceNormal.y, surfaceNormal.z, surfaceNormal.x);
|
||||
glm::vec3 perp2 = glm::vec3(surfaceNormal.z, surfaceNormal.x, surfaceNormal.y);
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
|
||||
for (int i=0; i<numSides+1; i++) {
|
||||
float r = ((float)i / (float)numSides) * PI * 2.0;
|
||||
float s = radius * sin(r);
|
||||
float c = radius * cos(r);
|
||||
glVertex3f
|
||||
(
|
||||
position.x + perp1.x * s + perp2.x * c,
|
||||
position.y + perp1.y * s + perp2.y * c,
|
||||
position.z + perp1.z * s + perp2.z * c
|
||||
);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
void renderOrientationDirections( glm::vec3 position, Orientation orientation, float size ) {
|
||||
glm::vec3 pRight = position + orientation.getRight() * size;
|
||||
glm::vec3 pUp = position + orientation.getUp() * size;
|
||||
|
|
|
@ -33,13 +33,19 @@ float angle_to(glm::vec3 head_pos, glm::vec3 source_pos, float render_yaw, float
|
|||
|
||||
float randFloat();
|
||||
void render_world_box();
|
||||
void render_vector(glm::vec3 * vec);
|
||||
int widthText(float scale, int mono, char const* string);
|
||||
float widthChar(float scale, int mono, char ch);
|
||||
void drawtext(int x, int y, float scale, float rotate, float thick, int mono,
|
||||
char const* string, float r=1.0, float g=1.0, float b=1.0);
|
||||
void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, glm::vec3 vec,
|
||||
float r=1.0, float g=1.0, float b=1.0);
|
||||
|
||||
void noiseTest(int w, int h);
|
||||
|
||||
void drawVector(glm::vec3* vector);
|
||||
|
||||
float angleBetween(glm::vec3 * v1, glm::vec3 * v2);
|
||||
|
||||
double diffclock(timeval *clock1,timeval *clock2);
|
||||
|
||||
void drawGroundPlaneGrid(float size);
|
||||
|
@ -48,6 +54,9 @@ void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, f
|
|||
|
||||
void renderOrientationDirections( glm::vec3 position, Orientation orientation, float size );
|
||||
|
||||
void renderSphereOutline(glm::vec3 position, float radius, int numSides, glm::vec3 cameraPosition);
|
||||
void renderCircle(glm::vec3 position, float radius, glm::vec3 surfaceNormal, int numSides );
|
||||
|
||||
|
||||
class oTestCase {
|
||||
public:
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <fstream> // to load voxels from file
|
||||
#include <SharedUtil.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PerfStat.h>
|
||||
#include <OctalCode.h>
|
||||
#include <pthread.h>
|
||||
#include "Log.h"
|
||||
|
@ -41,7 +42,8 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- .
|
|||
4,5,6, 4,6,7 }; // Z+ .
|
||||
|
||||
VoxelSystem::VoxelSystem() {
|
||||
_voxelsInArrays = _voxelsUpdated = 0;
|
||||
_voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0;
|
||||
_alwaysRenderFullVBO = true;
|
||||
_tree = new VoxelTree();
|
||||
pthread_mutex_init(&_bufferWriteLock, NULL);
|
||||
}
|
||||
|
@ -58,7 +60,7 @@ VoxelSystem::~VoxelSystem() {
|
|||
|
||||
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
||||
_tree->loadVoxelsFile(fileName, wantColorRandomizer);
|
||||
copyWrittenDataToReadArrays();
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) {
|
||||
|
@ -98,24 +100,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
switch(command) {
|
||||
case PACKET_HEADER_VOXEL_DATA:
|
||||
{
|
||||
double start = usecTimestampNow();
|
||||
PerformanceWarning warn(_renderWarningsOn, "readBitstreamToTree()");
|
||||
// ask the VoxelTree to read the bitstream into the tree
|
||||
_tree->readBitstreamToTree(voxelData, numBytes - 1);
|
||||
if (_renderWarningsOn && _tree->getNodesChangedFromBitstream()) {
|
||||
printLog("readBitstreamToTree()... getNodesChangedFromBitstream=%ld _tree->isDirty()=%s \n",
|
||||
_tree->getNodesChangedFromBitstream(), (_tree->isDirty() ? "yes" : "no") );
|
||||
}
|
||||
|
||||
double end = usecTimestampNow();
|
||||
double elapsedmsec = (end - start)/1000.0;
|
||||
if (_renderWarningsOn && elapsedmsec > 1) {
|
||||
if (elapsedmsec > 1000) {
|
||||
double elapsedsec = (end - start)/1000000.0;
|
||||
printLog("WARNING! readBitstreamToTree() took %lf seconds\n",elapsedsec);
|
||||
} else {
|
||||
printLog("WARNING! readBitstreamToTree() took %lf milliseconds\n",elapsedmsec);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PACKET_HEADER_ERASE_VOXEL:
|
||||
|
@ -138,7 +125,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
if (0==strcmp(command,(char*)"erase all")) {
|
||||
printLog("got Z message == erase all\n");
|
||||
_tree->eraseAllVoxels();
|
||||
_voxelsInArrays = 0; // better way to do this??
|
||||
_voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this??
|
||||
}
|
||||
if (0==strcmp(command,(char*)"add scene")) {
|
||||
printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n");
|
||||
|
@ -153,16 +140,29 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
}
|
||||
|
||||
void VoxelSystem::setupNewVoxelsForDrawing() {
|
||||
PerformanceWarning warn(_renderWarningsOn, "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated
|
||||
double start = usecTimestampNow();
|
||||
|
||||
double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished);
|
||||
double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0;
|
||||
|
||||
if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) {
|
||||
return; // bail early, it hasn't been long enough since the last time we ran
|
||||
}
|
||||
|
||||
double sinceLastViewCulling = (start - _lastViewCulling) / 1000.0;
|
||||
|
||||
// If the view frustum has changed, since last time, then remove nodes that are out of view
|
||||
if ((sinceLastViewCulling >= VIEW_CULLING_RATE_IN_MILLISECONDS) && hasViewChanged()) {
|
||||
_lastViewCulling = start;
|
||||
removeOutOfView();
|
||||
}
|
||||
|
||||
if (_tree->isDirty()) {
|
||||
PerformanceWarning warn(_renderWarningsOn, "calling... newTreeToArrays()");
|
||||
_callsToTreesToArrays++;
|
||||
|
||||
if (_alwaysRenderFullVBO) {
|
||||
_voxelsInWriteArrays = 0; // reset our VBO
|
||||
}
|
||||
_voxelsUpdated = newTreeToArrays(_tree->rootNode);
|
||||
_tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean
|
||||
} else {
|
||||
|
@ -172,78 +172,88 @@ void VoxelSystem::setupNewVoxelsForDrawing() {
|
|||
_voxelsDirty=true;
|
||||
}
|
||||
|
||||
if (_voxelsDirty) {
|
||||
// copy the newly written data to the arrays designated for reading
|
||||
copyWrittenDataToReadArrays();
|
||||
}
|
||||
// copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated
|
||||
copyWrittenDataToReadArrays();
|
||||
|
||||
double end = usecTimestampNow();
|
||||
double elapsedmsec = (end - start)/1000.0;
|
||||
if (_renderWarningsOn && elapsedmsec > 1) {
|
||||
if (elapsedmsec > 1000) {
|
||||
double elapsedsec = (end - start)/1000000.0;
|
||||
printLog("WARNING! newTreeToArrays() took %lf seconds %ld voxels updated\n", elapsedsec, _voxelsUpdated);
|
||||
} else {
|
||||
printLog("WARNING! newTreeToArrays() took %lf milliseconds %ld voxels updated\n", elapsedmsec, _voxelsUpdated);
|
||||
}
|
||||
}
|
||||
|
||||
_setupNewVoxelsForDrawingLastFinished = end;
|
||||
_setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
|
||||
}
|
||||
|
||||
void VoxelSystem::copyWrittenDataToReadArrays() {
|
||||
double start = usecTimestampNow();
|
||||
PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated
|
||||
if (_voxelsDirty && _voxelsUpdated) {
|
||||
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
||||
pthread_mutex_lock(&_bufferWriteLock);
|
||||
int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat);
|
||||
int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte);
|
||||
int bytesOfVertices = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat);
|
||||
int bytesOfColors = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte);
|
||||
memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices);
|
||||
memcpy(_readColorsArray, _writeColorsArray, bytesOfColors );
|
||||
_voxelsInReadArrays = _voxelsInWriteArrays;
|
||||
pthread_mutex_unlock(&_bufferWriteLock);
|
||||
}
|
||||
double end = usecTimestampNow();
|
||||
double elapsedmsec = (end - start)/1000.0;
|
||||
if (_renderWarningsOn && elapsedmsec > 1) {
|
||||
if (elapsedmsec > 1000) {
|
||||
double elapsedsec = (end - start)/1000000.0;
|
||||
printLog("WARNING! copyWrittenDataToReadArrays() took %lf seconds for %ld voxels %ld updated\n",
|
||||
elapsedsec, _voxelsInArrays, _voxelsUpdated);
|
||||
} else {
|
||||
printLog("WARNING! copyWrittenDataToReadArrays() took %lf milliseconds for %ld voxels %ld updated\n",
|
||||
elapsedmsec, _voxelsInArrays, _voxelsUpdated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int VoxelSystem::newTreeToArrays(VoxelNode* node) {
|
||||
assert(_viewFrustum); // you must set up _viewFrustum before calling this
|
||||
int voxelsUpdated = 0;
|
||||
float distanceToNode = node->distanceToCamera(*_viewFrustum);
|
||||
float boundary = boundaryDistanceForRenderLevel(*node->octalCode + 1);
|
||||
float childBoundary = boundaryDistanceForRenderLevel(*node->octalCode + 2);
|
||||
bool inBoundary = (distanceToNode <= boundary);
|
||||
bool inChildBoundary = (distanceToNode <= childBoundary);
|
||||
bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary));
|
||||
|
||||
bool shouldRender = false; // assume we don't need to render it
|
||||
// if it's colored, we might need to render it!
|
||||
if (node->isColored()) {
|
||||
float distanceToNode = node->distanceToCamera(*_viewFrustum);
|
||||
float boundary = boundaryDistanceForRenderLevel(node->getLevel());
|
||||
float childBoundary = boundaryDistanceForRenderLevel(node->getLevel() + 1);
|
||||
bool inBoundary = (distanceToNode <= boundary);
|
||||
bool inChildBoundary = (distanceToNode <= childBoundary);
|
||||
shouldRender = (node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary);
|
||||
}
|
||||
node->setShouldRender(shouldRender);
|
||||
// let children figure out their renderness
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (node->children[i]) {
|
||||
voxelsUpdated += newTreeToArrays(node->children[i]);
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
if (node->getChildAtIndex(i)) {
|
||||
voxelsUpdated += newTreeToArrays(node->getChildAtIndex(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (_alwaysRenderFullVBO) {
|
||||
voxelsUpdated += newway__updateNodeInArray(node);
|
||||
} else {
|
||||
voxelsUpdated += oldway__updateNodeInArray(node);
|
||||
}
|
||||
node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered
|
||||
return voxelsUpdated;
|
||||
}
|
||||
|
||||
int VoxelSystem::newway__updateNodeInArray(VoxelNode* node) {
|
||||
if (node->getShouldRender()) {
|
||||
glm::vec3 startVertex = node->getCorner();
|
||||
float voxelScale = node->getScale();
|
||||
glBufferIndex nodeIndex = _voxelsInWriteArrays;
|
||||
|
||||
// populate the array with points for the 8 vertices
|
||||
// and RGB color for each added vertex
|
||||
for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) {
|
||||
GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||
*(writeColorsAt +j) = node->getColor()[j % 3];
|
||||
}
|
||||
_voxelsInWriteArrays++; // our know vertices in the arrays
|
||||
return 1; // rendered
|
||||
}
|
||||
return 0; // not-rendered
|
||||
}
|
||||
|
||||
int VoxelSystem::oldway__updateNodeInArray(VoxelNode* node) {
|
||||
// Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us
|
||||
if (node->isDirty() && (shouldRender || node->isKnownBufferIndex())) {
|
||||
if (node->isDirty() && (node->getShouldRender() || node->isKnownBufferIndex())) {
|
||||
glm::vec3 startVertex;
|
||||
float voxelScale = 0;
|
||||
|
||||
// If we're should render, use our legit location and scale,
|
||||
if (node->getShouldRender()) {
|
||||
copyFirstVertexForCode(node->octalCode, (float*)&startVertex);
|
||||
voxelScale = (1 / powf(2, *node->octalCode));
|
||||
startVertex = node->getCorner();
|
||||
voxelScale = node->getScale();
|
||||
} else {
|
||||
// if we shouldn't render then set out location to some infinitely distant location,
|
||||
// and our scale as infinitely small
|
||||
|
@ -256,7 +266,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) {
|
|||
if (node->isKnownBufferIndex()) {
|
||||
nodeIndex = node->getBufferIndex();
|
||||
} else {
|
||||
nodeIndex = _voxelsInArrays;
|
||||
nodeIndex = _voxelsInWriteArrays;
|
||||
}
|
||||
|
||||
_voxelDirtyArray[nodeIndex] = true;
|
||||
|
@ -271,12 +281,11 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) {
|
|||
}
|
||||
if (!node->isKnownBufferIndex()) {
|
||||
node->setBufferIndex(nodeIndex);
|
||||
_voxelsInArrays++; // our know vertices in the arrays
|
||||
_voxelsInWriteArrays++; // our know vertices in the arrays
|
||||
}
|
||||
voxelsUpdated++;
|
||||
return 1; // updated!
|
||||
}
|
||||
node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered
|
||||
return voxelsUpdated;
|
||||
return 0; // not-updated
|
||||
}
|
||||
|
||||
VoxelSystem* VoxelSystem::clone() const {
|
||||
|
@ -290,10 +299,13 @@ void VoxelSystem::init() {
|
|||
_callsToTreesToArrays = 0;
|
||||
_setupNewVoxelsForDrawingLastFinished = 0;
|
||||
_setupNewVoxelsForDrawingLastElapsed = 0;
|
||||
_lastViewCulling = 0;
|
||||
|
||||
// When we change voxels representations in the arrays, we'll update this
|
||||
_voxelsDirty = false;
|
||||
_voxelsInArrays = 0;
|
||||
_voxelsInWriteArrays = 0;
|
||||
_voxelsInReadArrays = 0;
|
||||
_unusedArraySpace = 0;
|
||||
|
||||
// we will track individual dirty sections with this array of bools
|
||||
_voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM];
|
||||
|
@ -362,59 +374,60 @@ void VoxelSystem::init() {
|
|||
}
|
||||
|
||||
void VoxelSystem::updateVBOs() {
|
||||
double start = usecTimestampNow();
|
||||
PerformanceWarning warn(_renderWarningsOn, "updateVBOs()"); // would like to include _callsToTreesToArrays
|
||||
if (_voxelsDirty) {
|
||||
glBufferIndex segmentStart = 0;
|
||||
glBufferIndex segmentEnd = 0;
|
||||
bool inSegment = false;
|
||||
for (glBufferIndex i = 0; i < _voxelsInArrays; i++) {
|
||||
if (!inSegment) {
|
||||
if (_voxelDirtyArray[i]) {
|
||||
segmentStart = i;
|
||||
inSegment = true;
|
||||
_voxelDirtyArray[i] = false; // consider us clean!
|
||||
}
|
||||
} else {
|
||||
if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) {
|
||||
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);
|
||||
if (_alwaysRenderFullVBO) {
|
||||
glBufferIndex segmentStart = 0;
|
||||
glBufferIndex segmentEnd = _voxelsInWriteArrays;
|
||||
|
||||
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 {
|
||||
glBufferIndex segmentStart = 0;
|
||||
glBufferIndex segmentEnd = 0;
|
||||
bool inSegment = false;
|
||||
for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) {
|
||||
if (!inSegment) {
|
||||
if (_voxelDirtyArray[i]) {
|
||||
segmentStart = i;
|
||||
inSegment = true;
|
||||
_voxelDirtyArray[i] = false; // consider us clean!
|
||||
}
|
||||
} else {
|
||||
if (!_voxelDirtyArray[i] || (i == (_voxelsInWriteArrays - 1)) ) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_voxelsDirty = false;
|
||||
}
|
||||
double end = usecTimestampNow();
|
||||
double elapsedmsec = (end - start)/1000.0;
|
||||
if (_renderWarningsOn && elapsedmsec > 1) {
|
||||
if (elapsedmsec > 1) {
|
||||
if (elapsedmsec > 1000) {
|
||||
double elapsedsec = (end - start)/1000000.0;
|
||||
printLog("WARNING! updateVBOs() took %lf seconds after %d calls to newTreeToArrays()\n",
|
||||
elapsedsec, _callsToTreesToArrays);
|
||||
} else {
|
||||
printLog("WARNING! updateVBOs() took %lf milliseconds after %d calls to newTreeToArrays()\n",
|
||||
elapsedmsec, _callsToTreesToArrays);
|
||||
}
|
||||
} else {
|
||||
printLog("WARNING! updateVBOs() called after %d calls to newTreeToArrays()\n",_callsToTreesToArrays);
|
||||
}
|
||||
}
|
||||
_callsToTreesToArrays = 0; // clear it
|
||||
}
|
||||
|
||||
void VoxelSystem::render() {
|
||||
double start = usecTimestampNow();
|
||||
PerformanceWarning warn(_renderWarningsOn, "render()");
|
||||
glPushMatrix();
|
||||
updateVBOs();
|
||||
// tell OpenGL where to find vertex and color information
|
||||
|
@ -434,7 +447,7 @@ void VoxelSystem::render() {
|
|||
// draw the number of voxels we have
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
||||
glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE);
|
||||
glDrawElements(GL_TRIANGLES, 36 * _voxelsInArrays, GL_UNSIGNED_INT, 0);
|
||||
glDrawElements(GL_TRIANGLES, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
// deactivate vertex and color arrays after drawing
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
@ -447,23 +460,13 @@ void VoxelSystem::render() {
|
|||
|
||||
// scale back down to 1 so heads aren't massive
|
||||
glPopMatrix();
|
||||
double end = usecTimestampNow();
|
||||
double elapsedmsec = (end - start)/1000.0;
|
||||
if (_renderWarningsOn && elapsedmsec > 1) {
|
||||
if (elapsedmsec > 1000) {
|
||||
double elapsedsec = (end - start)/1000000.0;
|
||||
printLog("WARNING! render() took %lf seconds\n",elapsedsec);
|
||||
} else {
|
||||
printLog("WARNING! render() took %lf milliseconds\n",elapsedmsec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int VoxelSystem::_nodeCount = 0;
|
||||
|
||||
void VoxelSystem::killLocalVoxels() {
|
||||
_tree->eraseAllVoxels();
|
||||
_voxelsInArrays = 0; // better way to do this??
|
||||
_voxelsInWriteArrays = _voxelsInReadArrays = 0; // better way to do this??
|
||||
//setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
@ -584,4 +587,33 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) {
|
|||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
// "Remove" voxels from the tree that are not in view. We don't actually delete them,
|
||||
// we remove them from the tree and place them into a holding area for later deletion
|
||||
bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) {
|
||||
VoxelSystem* thisVoxelSystem = (VoxelSystem*) extraData;
|
||||
_nodeCount++;
|
||||
// Need to operate on our child nodes, so we can remove them
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
VoxelNode* childNode = node->getChildAtIndex(i);
|
||||
if (childNode && !childNode->isInView(*thisVoxelSystem->_viewFrustum)) {
|
||||
node->removeChildAtIndex(i);
|
||||
thisVoxelSystem->_removedVoxels.insert(childNode);
|
||||
}
|
||||
}
|
||||
return true; // keep going!
|
||||
}
|
||||
|
||||
bool VoxelSystem::hasViewChanged() {
|
||||
bool result = false; // assume the best
|
||||
if (_viewFrustum && !_lastKnowViewFrustum.matches(_viewFrustum)) {
|
||||
result = true;
|
||||
_lastKnowViewFrustum = *_viewFrustum; // save last known
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void VoxelSystem::removeOutOfView() {
|
||||
PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); // would like to include removedCount, _nodeCount, _removedVoxels.count()
|
||||
_nodeCount = 0;
|
||||
_tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)this);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
void render();
|
||||
|
||||
unsigned long getVoxelsUpdated() const {return _voxelsUpdated;};
|
||||
unsigned long getVoxelsRendered() const {return _voxelsInArrays;};
|
||||
unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;};
|
||||
|
||||
void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; };
|
||||
void setCamera(Camera* newCamera) { _camera = newCamera; };
|
||||
|
@ -61,9 +61,13 @@ public:
|
|||
void killLocalVoxels();
|
||||
void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; };
|
||||
bool getRenderPipelineWarnings() const { return _renderWarningsOn; };
|
||||
|
||||
void removeOutOfView();
|
||||
bool hasViewChanged();
|
||||
|
||||
private:
|
||||
int _callsToTreesToArrays;
|
||||
VoxelNodeBag _removedVoxels;
|
||||
|
||||
bool _renderWarningsOn;
|
||||
// Operation functions for tree recursion methods
|
||||
|
@ -74,6 +78,10 @@ private:
|
|||
static bool falseColorizeInViewOperation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData);
|
||||
static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData);
|
||||
static bool removeOutOfViewOperation(VoxelNode* node, void* extraData);
|
||||
|
||||
int newway__updateNodeInArray(VoxelNode* node);
|
||||
int oldway__updateNodeInArray(VoxelNode* node);
|
||||
|
||||
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
|
||||
static float _maxDistance;
|
||||
|
@ -88,11 +96,15 @@ private:
|
|||
GLubyte* _writeColorsArray;
|
||||
bool* _voxelDirtyArray;
|
||||
unsigned long _voxelsUpdated;
|
||||
unsigned long _voxelsInArrays;
|
||||
unsigned long _voxelsInWriteArrays;
|
||||
unsigned long _voxelsInReadArrays;
|
||||
unsigned long _unusedArraySpace;
|
||||
|
||||
bool _alwaysRenderFullVBO;
|
||||
|
||||
double _setupNewVoxelsForDrawingLastElapsed;
|
||||
double _setupNewVoxelsForDrawingLastFinished;
|
||||
double _lastViewCulling;
|
||||
|
||||
GLuint _vboVerticesID;
|
||||
GLuint _vboNormalsID;
|
||||
|
@ -101,6 +113,7 @@ private:
|
|||
pthread_mutex_t _bufferWriteLock;
|
||||
|
||||
ViewFrustum* _viewFrustum;
|
||||
ViewFrustum _lastKnowViewFrustum;
|
||||
|
||||
int newTreeToArrays(VoxelNode *currentNode);
|
||||
void setupNewVoxelsForDrawing();
|
||||
|
|
|
@ -14,14 +14,6 @@
|
|||
//
|
||||
// Welcome Aboard!
|
||||
//
|
||||
//
|
||||
// Keyboard Commands:
|
||||
//
|
||||
// / = toggle stats display
|
||||
// spacebar = reset gyros/head position
|
||||
// h = render Head facing yourself (mirror)
|
||||
// l = show incoming gyro levels
|
||||
//
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
#include <math.h>
|
||||
|
@ -69,7 +61,6 @@
|
|||
|
||||
#include "Camera.h"
|
||||
#include "Avatar.h"
|
||||
#include "Texture.h"
|
||||
#include <AgentList.h>
|
||||
#include <AgentTypes.h>
|
||||
#include "VoxelSystem.h"
|
||||
|
@ -443,17 +434,22 @@ void updateAvatar(float frametime) {
|
|||
myAvatar.setCameraAspectRatio(::viewFrustum.getAspectRatio());
|
||||
myAvatar.setCameraNearClip(::viewFrustum.getNearClip());
|
||||
myAvatar.setCameraFarClip(::viewFrustum.getFarClip());
|
||||
|
||||
// Send my stream of head/hand data to the avatar mixer and voxel server
|
||||
unsigned char broadcastString[200];
|
||||
*broadcastString = PACKET_HEADER_HEAD_DATA;
|
||||
|
||||
int broadcastBytes = myAvatar.getBroadcastData(broadcastString + 1);
|
||||
broadcastBytes++;
|
||||
AgentList* agentList = AgentList::getInstance();
|
||||
|
||||
const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL, AGENT_TYPE_AVATAR_MIXER};
|
||||
|
||||
AgentList::getInstance()->broadcastToAgents(broadcastString, broadcastBytes, broadcastReceivers, 2);
|
||||
if (agentList->getOwnerID() != UNKNOWN_AGENT_ID) {
|
||||
// if I know my ID, send head/hand data to the avatar mixer and voxel server
|
||||
unsigned char broadcastString[200];
|
||||
unsigned char* endOfBroadcastStringWrite = broadcastString;
|
||||
|
||||
*(endOfBroadcastStringWrite++) = PACKET_HEADER_HEAD_DATA;
|
||||
endOfBroadcastStringWrite += packAgentId(endOfBroadcastStringWrite, agentList->getOwnerID());
|
||||
|
||||
endOfBroadcastStringWrite += myAvatar.getBroadcastData(endOfBroadcastStringWrite);
|
||||
|
||||
const char broadcastReceivers[2] = {AGENT_TYPE_VOXEL, AGENT_TYPE_AVATAR_MIXER};
|
||||
AgentList::getInstance()->broadcastToAgents(broadcastString, endOfBroadcastStringWrite - broadcastString, broadcastReceivers, sizeof(broadcastReceivers));
|
||||
}
|
||||
|
||||
// If I'm in paint mode, send a voxel out to VOXEL server agents.
|
||||
if (::paintOn) {
|
||||
|
@ -461,9 +457,9 @@ void updateAvatar(float frametime) {
|
|||
glm::vec3 avatarPos = myAvatar.getPosition();
|
||||
|
||||
// For some reason, we don't want to flip X and Z here.
|
||||
::paintingVoxel.x = avatarPos.x/10.0;
|
||||
::paintingVoxel.y = avatarPos.y/10.0;
|
||||
::paintingVoxel.z = avatarPos.z/10.0;
|
||||
::paintingVoxel.x = avatarPos.x / 10.0;
|
||||
::paintingVoxel.y = avatarPos.y / 10.0;
|
||||
::paintingVoxel.z = avatarPos.z / 10.0;
|
||||
|
||||
unsigned char* bufferOut;
|
||||
int sizeOut;
|
||||
|
@ -704,15 +700,14 @@ void displaySide(Camera& whichCamera) {
|
|||
float sphereRadius = 0.25f;
|
||||
glColor3f(1,0,0);
|
||||
glPushMatrix();
|
||||
glutSolidSphere( sphereRadius, 15, 15 );
|
||||
glutSolidSphere(sphereRadius, 15, 15);
|
||||
glPopMatrix();
|
||||
|
||||
//draw a grid ground plane....
|
||||
drawGroundPlaneGrid(10.f);
|
||||
|
||||
// Draw voxels
|
||||
if ( showingVoxels )
|
||||
{
|
||||
if (showingVoxels) {
|
||||
voxels.render();
|
||||
}
|
||||
|
||||
|
@ -722,7 +717,7 @@ void displaySide(Camera& whichCamera) {
|
|||
for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) {
|
||||
if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) {
|
||||
Avatar *avatar = (Avatar *)agent->getLinkedData();
|
||||
avatar->render(0);
|
||||
avatar->render(0, ::myCamera.getPosition());
|
||||
}
|
||||
}
|
||||
agentList->unlock();
|
||||
|
@ -734,7 +729,7 @@ void displaySide(Camera& whichCamera) {
|
|||
if (::frustumOn) renderViewFrustum(::viewFrustum);
|
||||
|
||||
//Render my own avatar
|
||||
myAvatar.render(::lookingInMirror);
|
||||
myAvatar.render(::lookingInMirror, ::myCamera.getPosition());
|
||||
|
||||
glPopMatrix();
|
||||
}
|
||||
|
@ -905,6 +900,8 @@ void displayOverlay() {
|
|||
audioScope.render();
|
||||
#endif
|
||||
|
||||
// noiseTest(WIDTH, HEIGHT);
|
||||
|
||||
if (displayHeadMouse && !::lookingInMirror && statsOn) {
|
||||
// Display small target box at center or head mouse target that can also be used to measure LOD
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
|
@ -996,15 +993,15 @@ void display(void)
|
|||
glMateriali(GL_FRONT, GL_SHININESS, 96);
|
||||
|
||||
// camera settings
|
||||
if ( ::lookingInMirror ) {
|
||||
if (::lookingInMirror) {
|
||||
// set the camera to looking at my own face
|
||||
myCamera.setTargetPosition ( myAvatar.getHeadPosition() );
|
||||
myCamera.setTargetYaw ( myAvatar.getBodyYaw() - 180.0f ); // 180 degrees from body yaw
|
||||
myCamera.setPitch ( 0.0 );
|
||||
myCamera.setRoll ( 0.0 );
|
||||
myCamera.setUpShift ( 0.0 );
|
||||
myCamera.setDistance ( 0.2 );
|
||||
myCamera.setTightness ( 100.0f );
|
||||
myCamera.setTargetPosition (myAvatar.getHeadPosition());
|
||||
myCamera.setTargetYaw (myAvatar.getBodyYaw() - 180.0f); // 180 degrees from body yaw
|
||||
myCamera.setPitch (0.0);
|
||||
myCamera.setRoll (0.0);
|
||||
myCamera.setUpShift (0.0);
|
||||
myCamera.setDistance (0.2);
|
||||
myCamera.setTightness (100.0f);
|
||||
} else {
|
||||
|
||||
//float firstPersonPitch = 20.0f;
|
||||
|
@ -1022,36 +1019,24 @@ void display(void)
|
|||
float thirdPersonDistance = 1.2f;
|
||||
float thirdPersonTightness = 8.0f;
|
||||
|
||||
if ( USING_FIRST_PERSON_EFFECT ) {
|
||||
if (USING_FIRST_PERSON_EFFECT) {
|
||||
float ff = 0.0;
|
||||
float min = 0.1;
|
||||
float max = 0.5;
|
||||
|
||||
if ( myAvatar.getIsNearInteractingOther()){
|
||||
if ( myAvatar.getSpeed() < max ) {
|
||||
if (myAvatar.getIsNearInteractingOther()){
|
||||
if (myAvatar.getSpeed() < max) {
|
||||
|
||||
float s = (myAvatar.getSpeed()- min)/max ;
|
||||
ff = 1.0 - s;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if ( ff < 0.8 ) {
|
||||
myAvatar.setDisplayingHead( true );
|
||||
} else {
|
||||
myAvatar.setDisplayingHead( false );
|
||||
}
|
||||
*/
|
||||
|
||||
//printf( "ff = %f\n", ff );
|
||||
|
||||
myCamera.setPitch ( thirdPersonPitch + ff * ( firstPersonPitch - thirdPersonPitch ));
|
||||
myCamera.setUpShift ( thirdPersonUpShift + ff * ( firstPersonUpShift - thirdPersonUpShift ));
|
||||
myCamera.setDistance ( thirdPersonDistance + ff * ( firstPersonDistance - thirdPersonDistance ));
|
||||
myCamera.setTightness ( thirdPersonTightness + ff * ( firstPersonTightness - thirdPersonTightness ));
|
||||
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 ) {
|
||||
|
@ -1085,13 +1070,23 @@ void display(void)
|
|||
myCamera.setTightness(thirdPersonTightness);
|
||||
}
|
||||
|
||||
myCamera.setTargetPosition( myAvatar.getHeadPosition() );
|
||||
myCamera.setTargetYaw ( myAvatar.getBodyYaw() );
|
||||
myCamera.setRoll ( 0.0 );
|
||||
myCamera.setTargetPosition(myAvatar.getHeadPosition());
|
||||
myCamera.setTargetYaw (myAvatar.getBodyYaw());
|
||||
myCamera.setRoll (0.0);
|
||||
}
|
||||
|
||||
// important...
|
||||
|
||||
myCamera.update( 1.f/FPS );
|
||||
|
||||
// Render anything (like HUD items) that we want to be in 3D but not in worldspace
|
||||
const float HUD_Z_OFFSET = -5.f;
|
||||
glPushMatrix();
|
||||
glm::vec3 test(0.5, 0.5, 0.5);
|
||||
glTranslatef(1, 1, HUD_Z_OFFSET);
|
||||
drawVector(&test);
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
// Note: whichCamera is used to pick between the normal camera myCamera for our
|
||||
// main camera, vs, an alternate camera. The alternate camera we support right now
|
||||
|
@ -1107,11 +1102,11 @@ void display(void)
|
|||
if (::viewFrustumFromOffset && ::frustumOn) {
|
||||
|
||||
// set the camera to third-person view but offset so we can see the frustum
|
||||
viewFrustumOffsetCamera.setTargetYaw( ::viewFrustumOffsetYaw + myAvatar.getBodyYaw() );
|
||||
viewFrustumOffsetCamera.setPitch ( ::viewFrustumOffsetPitch );
|
||||
viewFrustumOffsetCamera.setRoll ( ::viewFrustumOffsetRoll );
|
||||
viewFrustumOffsetCamera.setUpShift ( ::viewFrustumOffsetUp );
|
||||
viewFrustumOffsetCamera.setDistance ( ::viewFrustumOffsetDistance );
|
||||
viewFrustumOffsetCamera.setTargetYaw(::viewFrustumOffsetYaw + myAvatar.getBodyYaw() );
|
||||
viewFrustumOffsetCamera.setPitch (::viewFrustumOffsetPitch );
|
||||
viewFrustumOffsetCamera.setRoll (::viewFrustumOffsetRoll );
|
||||
viewFrustumOffsetCamera.setUpShift (::viewFrustumOffsetUp );
|
||||
viewFrustumOffsetCamera.setDistance (::viewFrustumOffsetDistance);
|
||||
viewFrustumOffsetCamera.update(1.f/FPS);
|
||||
whichCamera = viewFrustumOffsetCamera;
|
||||
}
|
||||
|
@ -1121,11 +1116,11 @@ void display(void)
|
|||
// or could be viewFrustumOffsetCamera if in offset mode
|
||||
// I changed the ordering here - roll is FIRST (JJV)
|
||||
|
||||
glRotatef ( whichCamera.getRoll(), IDENTITY_FRONT.x, IDENTITY_FRONT.y, IDENTITY_FRONT.z );
|
||||
glRotatef ( whichCamera.getPitch(), IDENTITY_RIGHT.x, IDENTITY_RIGHT.y, IDENTITY_RIGHT.z );
|
||||
glRotatef ( 180.0 - whichCamera.getYaw(), IDENTITY_UP.x, IDENTITY_UP.y, IDENTITY_UP.z );
|
||||
glRotatef ( whichCamera.getRoll(), IDENTITY_FRONT.x, IDENTITY_FRONT.y, IDENTITY_FRONT.z);
|
||||
glRotatef ( whichCamera.getPitch(), IDENTITY_RIGHT.x, IDENTITY_RIGHT.y, IDENTITY_RIGHT.z);
|
||||
glRotatef (180.0 - whichCamera.getYaw(), IDENTITY_UP.x, IDENTITY_UP.y, IDENTITY_UP.z );
|
||||
|
||||
glTranslatef( -whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z );
|
||||
glTranslatef(-whichCamera.getPosition().x, -whichCamera.getPosition().y, -whichCamera.getPosition().z);
|
||||
|
||||
if (::oculusOn) {
|
||||
displayOculus(whichCamera);
|
||||
|
@ -1397,8 +1392,7 @@ void initMenu() {
|
|||
menuColumnDebug->addRow("Show TRUE Colors", doTrueVoxelColors);
|
||||
}
|
||||
|
||||
void testPointToVoxel()
|
||||
{
|
||||
void testPointToVoxel() {
|
||||
float y=0;
|
||||
float z=0;
|
||||
float s=0.1;
|
||||
|
@ -1450,8 +1444,7 @@ void setupPaintingVoxel() {
|
|||
shiftPaintingColor();
|
||||
}
|
||||
|
||||
void addRandomSphere(bool wantColorRandomizer)
|
||||
{
|
||||
void addRandomSphere(bool wantColorRandomizer) {
|
||||
float r = randFloatInRange(0.05,0.1);
|
||||
float xc = randFloatInRange(r,(1-r));
|
||||
float yc = randFloatInRange(r,(1-r));
|
||||
|
@ -1468,7 +1461,6 @@ void addRandomSphere(bool wantColorRandomizer)
|
|||
voxels.createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer);
|
||||
}
|
||||
|
||||
|
||||
const float KEYBOARD_YAW_RATE = 0.8;
|
||||
const float KEYBOARD_PITCH_RATE = 0.6;
|
||||
const float KEYBOARD_STRAFE_RATE = 0.03;
|
||||
|
@ -1522,7 +1514,6 @@ void specialkey(int k, int x, int y) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void keyUp(unsigned char k, int x, int y) {
|
||||
if (::chatEntryOn) {
|
||||
myAvatar.setKeyState(NO_KEY_DOWN);
|
||||
|
@ -1537,8 +1528,7 @@ void keyUp(unsigned char k, int x, int y) {
|
|||
if (k == 'd') myAvatar.setDriveKeys(ROT_RIGHT, 0);
|
||||
}
|
||||
|
||||
void key(unsigned char k, int x, int y)
|
||||
{
|
||||
void key(unsigned char k, int x, int y) {
|
||||
if (::chatEntryOn) {
|
||||
if (chatEntry.key(k)) {
|
||||
myAvatar.setKeyState(k == '\b' || k == 127 ? // backspace or delete
|
||||
|
@ -1687,18 +1677,16 @@ void idle(void) {
|
|||
|
||||
// update behaviors for avatar hand movement: handControl takes mouse values as input,
|
||||
// and gives back 3D values modulated for smooth transitioning between interaction modes.
|
||||
handControl.update( mouseX, mouseY );
|
||||
myAvatar.setHandMovementValues( handControl.getValues() );
|
||||
handControl.update(mouseX, mouseY);
|
||||
myAvatar.setHandMovementValues(handControl.getValues());
|
||||
|
||||
// tell my avatar if the mouse is being pressed...
|
||||
if ( mousePressed == 1 ) {
|
||||
myAvatar.setMousePressed( true );
|
||||
} else {
|
||||
myAvatar.setMousePressed( false );
|
||||
}
|
||||
|
||||
if (mousePressed) {
|
||||
myAvatar.setMousePressed(mousePressed);
|
||||
}
|
||||
|
||||
// walking triggers the handControl to stop
|
||||
if ( myAvatar.getMode() == AVATAR_MODE_WALKING ) {
|
||||
if (myAvatar.getMode() == AVATAR_MODE_WALKING) {
|
||||
handControl.stop();
|
||||
}
|
||||
|
||||
|
@ -1789,10 +1777,6 @@ void reshape(int width, int height) {
|
|||
glLoadIdentity();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Find and return the gravity vector at this location
|
||||
glm::vec3 getGravity(glm::vec3 pos) {
|
||||
//
|
||||
|
@ -1851,8 +1835,7 @@ void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) {
|
|||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
int main(int argc, const char * argv[]) {
|
||||
voxels.setViewFrustum(&::viewFrustum);
|
||||
|
||||
shared_lib::printLog = & ::printLog;
|
||||
|
@ -1892,7 +1875,7 @@ int main(int argc, const char * argv[])
|
|||
|
||||
#ifdef _WIN32
|
||||
WSADATA WsaData;
|
||||
int wsaresult = WSAStartup( MAKEWORD(2,2), &WsaData );
|
||||
int wsaresult = WSAStartup(MAKEWORD(2,2), &WsaData);
|
||||
#endif
|
||||
|
||||
// start the agentList threads
|
||||
|
|
|
@ -128,8 +128,8 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
|||
// called on the other agents - assigns it to my views of the others
|
||||
int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
|
||||
// increment to push past the packet header
|
||||
sourceBuffer++;
|
||||
// increment to push past the packet header and agent ID
|
||||
sourceBuffer += sizeof(PACKET_HEADER_HEAD_DATA) + sizeof(uint16_t);
|
||||
|
||||
unsigned char* startPosition = sourceBuffer;
|
||||
|
||||
|
|
|
@ -62,8 +62,9 @@ AgentList::AgentList(char newOwnerType, unsigned int newSocketListenPort) :
|
|||
_agentBuckets(),
|
||||
_numAgents(0),
|
||||
agentSocket(newSocketListenPort),
|
||||
ownerType(newOwnerType),
|
||||
_ownerType(newOwnerType),
|
||||
socketListenPort(newSocketListenPort),
|
||||
_ownerID(UNKNOWN_AGENT_ID),
|
||||
lastAgentId(0) {
|
||||
pthread_mutex_init(&mutex, 0);
|
||||
}
|
||||
|
@ -81,10 +82,6 @@ UDPSocket& AgentList::getAgentSocket() {
|
|||
return agentSocket;
|
||||
}
|
||||
|
||||
char AgentList::getOwnerType() {
|
||||
return ownerType;
|
||||
}
|
||||
|
||||
unsigned int AgentList::getSocketListenPort() {
|
||||
return socketListenPort;
|
||||
}
|
||||
|
@ -92,7 +89,7 @@ unsigned int AgentList::getSocketListenPort() {
|
|||
void AgentList::processAgentData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes) {
|
||||
switch (((char *)packetData)[0]) {
|
||||
case PACKET_HEADER_DOMAIN: {
|
||||
updateList(packetData, dataBytes);
|
||||
processDomainServerList(packetData, dataBytes);
|
||||
break;
|
||||
}
|
||||
case PACKET_HEADER_PING: {
|
||||
|
@ -203,7 +200,7 @@ void AgentList::increaseAgentId() {
|
|||
++lastAgentId;
|
||||
}
|
||||
|
||||
int AgentList::updateList(unsigned char *packetData, size_t dataBytes) {
|
||||
int AgentList::processDomainServerList(unsigned char *packetData, size_t dataBytes) {
|
||||
int readAgents = 0;
|
||||
|
||||
char agentType;
|
||||
|
@ -218,14 +215,17 @@ int AgentList::updateList(unsigned char *packetData, size_t dataBytes) {
|
|||
unsigned char *readPtr = packetData + 1;
|
||||
unsigned char *startPtr = packetData;
|
||||
|
||||
while((readPtr - startPtr) < dataBytes) {
|
||||
while((readPtr - startPtr) < dataBytes - sizeof(uint16_t)) {
|
||||
agentType = *readPtr++;
|
||||
readPtr += unpackAgentId(readPtr, (uint16_t *)&agentId);
|
||||
readPtr += unpackSocket(readPtr, (sockaddr *)&agentPublicSocket);
|
||||
readPtr += unpackSocket(readPtr, (sockaddr *)&agentLocalSocket);
|
||||
|
||||
addOrUpdateAgent((sockaddr *)&agentPublicSocket, (sockaddr *)&agentLocalSocket, agentType, agentId);
|
||||
}
|
||||
}
|
||||
|
||||
// read out our ID from the packet
|
||||
unpackAgentId(readPtr, &_ownerID);
|
||||
|
||||
return readAgents;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ extern char DOMAIN_HOSTNAME[];
|
|||
extern char DOMAIN_IP[100]; // IP Address will be re-set by lookup on startup
|
||||
extern const int DOMAINSERVER_PORT;
|
||||
|
||||
const int UNKNOWN_AGENT_ID = -1;
|
||||
|
||||
class AgentListIterator;
|
||||
|
||||
class AgentList {
|
||||
|
@ -56,7 +58,7 @@ public:
|
|||
void lock() { pthread_mutex_lock(&mutex); }
|
||||
void unlock() { pthread_mutex_unlock(&mutex); }
|
||||
|
||||
int updateList(unsigned char *packetData, size_t dataBytes);
|
||||
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
||||
|
||||
Agent* agentWithAddress(sockaddr *senderAddress);
|
||||
Agent* agentWithID(uint16_t agentID);
|
||||
|
@ -70,9 +72,13 @@ public:
|
|||
int updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes);
|
||||
|
||||
void broadcastToAgents(unsigned char *broadcastData, size_t dataBytes, const char* agentTypes, int numAgentTypes);
|
||||
char getOwnerType();
|
||||
unsigned int getSocketListenPort();
|
||||
|
||||
char getOwnerType() const { return _ownerType; }
|
||||
|
||||
uint16_t getOwnerID() const { return _ownerID; }
|
||||
void setOwnerID(uint16_t ownerID) { _ownerID = ownerID; }
|
||||
|
||||
Agent* soloAgentOfType(char agentType);
|
||||
|
||||
void startSilentAgentRemovalThread();
|
||||
|
@ -96,8 +102,9 @@ private:
|
|||
Agent** _agentBuckets[MAX_NUM_AGENTS / AGENTS_PER_BUCKET];
|
||||
int _numAgents;
|
||||
UDPSocket agentSocket;
|
||||
char ownerType;
|
||||
char _ownerType;
|
||||
unsigned int socketListenPort;
|
||||
uint16_t _ownerID;
|
||||
uint16_t lastAgentId;
|
||||
pthread_t removeSilentAgentsThread;
|
||||
pthread_t checkInWithDomainServerThread;
|
||||
|
|
|
@ -97,6 +97,8 @@ void AudioRingBuffer::setBearing(float newBearing) {
|
|||
bearing = newBearing;
|
||||
}
|
||||
|
||||
const int AGENT_LOOPBACK_MODIFIER = 307;
|
||||
|
||||
int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
if (numBytes > (bufferLengthSamples * sizeof(int16_t))) {
|
||||
|
||||
|
@ -111,7 +113,19 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
attenuationRatio = attenuationByte / 255.0f;
|
||||
|
||||
memcpy(&bearing, dataPtr, sizeof(float));
|
||||
dataPtr += sizeof(float);
|
||||
dataPtr += sizeof(bearing);
|
||||
|
||||
if (bearing > 180 || bearing < -180) {
|
||||
// we were passed an invalid bearing because this agent wants loopback (pressed the H key)
|
||||
_shouldLoopbackForAgent = true;
|
||||
|
||||
// correct the bearing
|
||||
bearing = bearing > 0
|
||||
? bearing - AGENT_LOOPBACK_MODIFIER
|
||||
: bearing + AGENT_LOOPBACK_MODIFIER;
|
||||
} else {
|
||||
_shouldLoopbackForAgent = false;
|
||||
}
|
||||
|
||||
sourceBuffer = dataPtr;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
void setAttenuationRatio(float newAttenuation);
|
||||
float getBearing();
|
||||
void setBearing(float newBearing);
|
||||
|
||||
bool shouldLoopbackForAgent() const { return _shouldLoopbackForAgent; }
|
||||
|
||||
short diffLastWriteNextOutput();
|
||||
private:
|
||||
|
@ -49,6 +51,7 @@ private:
|
|||
int16_t *buffer;
|
||||
bool started;
|
||||
bool _shouldBeAddedToMix;
|
||||
bool _shouldLoopbackForAgent;
|
||||
};
|
||||
|
||||
#endif /* defined(__interface__AudioRingBuffer__) */
|
||||
|
|
|
@ -13,19 +13,20 @@
|
|||
#ifndef hifi_PacketHeaders_h
|
||||
#define hifi_PacketHeaders_h
|
||||
|
||||
const char PACKET_HEADER_DOMAIN = 'D';
|
||||
const char PACKET_HEADER_PING = 'P';
|
||||
const char PACKET_HEADER_PING_REPLY = 'R';
|
||||
const char PACKET_HEADER_HEAD_DATA = 'H';
|
||||
const char PACKET_HEADER_Z_COMMAND = 'Z';
|
||||
const char PACKET_HEADER_INJECT_AUDIO = 'I';
|
||||
const char PACKET_HEADER_SET_VOXEL = 'S';
|
||||
const char PACKET_HEADER_ERASE_VOXEL = 'E';
|
||||
const char PACKET_HEADER_VOXEL_DATA = 'V';
|
||||
const char PACKET_HEADER_BULK_AVATAR_DATA = 'X';
|
||||
const char PACKET_HEADER_TRANSMITTER_DATA = 't';
|
||||
const char PACKET_HEADER_ENVIRONMENT_DATA = 'e';
|
||||
const char PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L';
|
||||
const char PACKET_HEADER_DOMAIN_RFD = 'C';
|
||||
typedef char PACKET_HEADER;
|
||||
const PACKET_HEADER PACKET_HEADER_DOMAIN = 'D';
|
||||
const PACKET_HEADER PACKET_HEADER_PING = 'P';
|
||||
const PACKET_HEADER PACKET_HEADER_PING_REPLY = 'R';
|
||||
const PACKET_HEADER PACKET_HEADER_HEAD_DATA = 'H';
|
||||
const PACKET_HEADER PACKET_HEADER_Z_COMMAND = 'Z';
|
||||
const PACKET_HEADER PACKET_HEADER_INJECT_AUDIO = 'I';
|
||||
const PACKET_HEADER PACKET_HEADER_SET_VOXEL = 'S';
|
||||
const PACKET_HEADER PACKET_HEADER_ERASE_VOXEL = 'E';
|
||||
const PACKET_HEADER PACKET_HEADER_VOXEL_DATA = 'V';
|
||||
const PACKET_HEADER PACKET_HEADER_BULK_AVATAR_DATA = 'X';
|
||||
const PACKET_HEADER PACKET_HEADER_TRANSMITTER_DATA = 't';
|
||||
const PACKET_HEADER PACKET_HEADER_ENVIRONMENT_DATA = 'e';
|
||||
const PACKET_HEADER PACKET_HEADER_DOMAIN_LIST_REQUEST = 'L';
|
||||
const PACKET_HEADER PACKET_HEADER_DOMAIN_RFD = 'C';
|
||||
|
||||
#endif
|
||||
|
|
|
@ -103,3 +103,20 @@ int PerfStat::DumpStats(char** array) {
|
|||
return lineCount;
|
||||
}
|
||||
|
||||
|
||||
// Destructor handles recording all of our stats
|
||||
PerformanceWarning::~PerformanceWarning() {
|
||||
double end = usecTimestampNow();
|
||||
double elapsedmsec = (end - _start) / 1000.0;
|
||||
if (_renderWarningsOn && elapsedmsec > 1) {
|
||||
if (elapsedmsec > 1000) {
|
||||
double elapsedsec = (end - _start) / 1000000.0;
|
||||
printLog("WARNING! %s took %lf seconds\n", _message, elapsedsec);
|
||||
} else {
|
||||
printLog("WARNING! %s took %lf milliseconds\n", _message, elapsedmsec);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define __hifi__PerfStat__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "SharedUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define snprintf _snprintf
|
||||
|
@ -81,5 +82,19 @@ public:
|
|||
|
||||
typedef std::map<std::string,PerfStatHistory,std::less<std::string> >::iterator PerfStatMapItr;
|
||||
|
||||
class PerformanceWarning {
|
||||
private:
|
||||
double _start;
|
||||
const char* _message;
|
||||
bool _renderWarningsOn;
|
||||
public:
|
||||
PerformanceWarning(bool renderWarnings, const char* message) :
|
||||
_start(usecTimestampNow()),
|
||||
_message(message),
|
||||
_renderWarningsOn(renderWarnings) { };
|
||||
|
||||
~PerformanceWarning();
|
||||
};
|
||||
|
||||
|
||||
#endif /* defined(__hifi__PerfStat__) */
|
||||
|
|
28
libraries/shared/src/Stacktrace.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// Stacktrace.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 5/6/13.
|
||||
//
|
||||
//
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <execinfo.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "Stacktrace.h"
|
||||
|
||||
const int NUMBER_OF_STACK_ENTRIES = 20;
|
||||
|
||||
void printStacktrace(int signal) {
|
||||
void* array[NUMBER_OF_STACK_ENTRIES];
|
||||
|
||||
// get void*'s for all entries on the stack
|
||||
size_t size = backtrace(array, NUMBER_OF_STACK_ENTRIES);
|
||||
|
||||
// print out all the frames to stderr
|
||||
fprintf(stderr, "Error: signal %d:\n", signal);
|
||||
backtrace_symbols_fd(array, size, 2);
|
||||
exit(1);
|
||||
}
|
16
libraries/shared/src/Stacktrace.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// Stacktrace.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 5/6/13.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __hifi__Stacktrace__
|
||||
#define __hifi__Stacktrace__
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void printStacktrace(int signal);
|
||||
|
||||
#endif /* defined(__hifi__Stacktrace__) */
|
18
libraries/voxels/src/AABox.cpp
Executable file → Normal file
|
@ -14,8 +14,9 @@
|
|||
|
||||
|
||||
void AABox::scale(float scale) {
|
||||
_corner = _corner*scale;
|
||||
_size = _size*scale;
|
||||
_corner = _corner * scale;
|
||||
_size = _size * scale;
|
||||
_center = _center * scale;
|
||||
}
|
||||
|
||||
|
||||
|
@ -36,6 +37,7 @@ void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) {
|
|||
_size.z = -size.z;
|
||||
_corner.z -= _size.z;
|
||||
}
|
||||
_center = _corner + (_size * 0.5f);
|
||||
}
|
||||
|
||||
glm::vec3 AABox::getVertexP(const glm::vec3 &normal) const {
|
||||
|
@ -101,15 +103,15 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
}
|
||||
// check each axis
|
||||
float axisDistance;
|
||||
if (findIntersection(origin.x, direction.x, _corner.x, _size.x, axisDistance) && axisDistance >= 0 &&
|
||||
if ((findIntersection(origin.x, direction.x, _corner.x, _size.x, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
|
||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z) ||
|
||||
findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z)) ||
|
||||
(findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x) &&
|
||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z) ||
|
||||
findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z)) ||
|
||||
(findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 &&
|
||||
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
|
||||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x)) {
|
||||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x))) {
|
||||
distance = axisDistance;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -34,12 +34,14 @@ public:
|
|||
|
||||
const glm::vec3& getCorner() const { return _corner; };
|
||||
const glm::vec3& getSize() const { return _size; };
|
||||
const glm::vec3& getCenter() const { return _center; };
|
||||
|
||||
bool contains(const glm::vec3& point) const;
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||
|
||||
private:
|
||||
glm::vec3 _corner;
|
||||
glm::vec3 _center;
|
||||
glm::vec3 _size;
|
||||
};
|
||||
|
||||
|
|
|
@ -224,6 +224,53 @@ int ViewFrustum::boxInFrustum(const AABox& box) const {
|
|||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
bool ViewFrustum::matches(const ViewFrustum& compareTo) const {
|
||||
bool debug = false;
|
||||
bool result = compareTo._position == _position &&
|
||||
compareTo._direction == _direction &&
|
||||
compareTo._up == _up &&
|
||||
compareTo._right == _right &&
|
||||
compareTo._fieldOfView == _fieldOfView &&
|
||||
compareTo._aspectRatio == _aspectRatio &&
|
||||
compareTo._nearClip == _nearClip &&
|
||||
compareTo._farClip == _farClip;
|
||||
|
||||
if (!result && debug) {
|
||||
printLog("ViewFrustum::matches()... result=%s\n", (result ? "yes" : "no"));
|
||||
printLog("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f\n",
|
||||
(compareTo._position == _position ? "MATCHES " : "NO MATCH"),
|
||||
compareTo._position.x, compareTo._position.y, compareTo._position.z,
|
||||
_position.x, _position.y, _position.z );
|
||||
printLog("%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f\n",
|
||||
(compareTo._direction == _direction ? "MATCHES " : "NO MATCH"),
|
||||
compareTo._direction.x, compareTo._direction.y, compareTo._direction.z,
|
||||
_direction.x, _direction.y, _direction.z );
|
||||
printLog("%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f\n",
|
||||
(compareTo._up == _up ? "MATCHES " : "NO MATCH"),
|
||||
compareTo._up.x, compareTo._up.y, compareTo._up.z,
|
||||
_up.x, _up.y, _up.z );
|
||||
printLog("%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f\n",
|
||||
(compareTo._right == _right ? "MATCHES " : "NO MATCH"),
|
||||
compareTo._right.x, compareTo._right.y, compareTo._right.z,
|
||||
_right.x, _right.y, _right.z );
|
||||
printLog("%s -- compareTo._fieldOfView=%f _fieldOfView=%f\n",
|
||||
(compareTo._fieldOfView == _fieldOfView ? "MATCHES " : "NO MATCH"),
|
||||
compareTo._fieldOfView, _fieldOfView);
|
||||
printLog("%s -- compareTo._aspectRatio=%f _aspectRatio=%f\n",
|
||||
(compareTo._aspectRatio == _aspectRatio ? "MATCHES " : "NO MATCH"),
|
||||
compareTo._aspectRatio, _aspectRatio);
|
||||
printLog("%s -- compareTo._nearClip=%f _nearClip=%f\n",
|
||||
(compareTo._nearClip == _nearClip ? "MATCHES " : "NO MATCH"),
|
||||
compareTo._nearClip, _nearClip);
|
||||
printLog("%s -- compareTo._farClip=%f _farClip=%f\n",
|
||||
(compareTo._farClip == _farClip ? "MATCHES " : "NO MATCH"),
|
||||
compareTo._farClip, _farClip);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ViewFrustum::computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const {
|
||||
origin = _nearTopLeft + x*(_nearTopRight - _nearTopLeft) + y*(_nearBottomLeft - _nearTopLeft);
|
||||
|
|
|
@ -98,6 +98,9 @@ public:
|
|||
int sphereInFrustum(const glm::vec3& center, float radius) const;
|
||||
int boxInFrustum(const AABox& box) const;
|
||||
|
||||
// some frustum comparisons
|
||||
bool matches(const ViewFrustum& compareTo) const;
|
||||
bool matches(const ViewFrustum* compareTo) const { return matches(*compareTo); };
|
||||
void computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
|
||||
#include <limits.h>
|
||||
|
||||
const int TREE_SCALE = 100;
|
||||
|
||||
const int NUMBER_OF_CHILDREN = 8;
|
||||
const int MAX_VOXEL_PACKET_SIZE = 1492;
|
||||
const int MAX_TREE_SLICE_BYTES = 26;
|
||||
const int TREE_SCALE = 10;
|
||||
const int MAX_VOXELS_PER_SYSTEM = 250000;
|
||||
const int VERTICES_PER_VOXEL = 24;
|
||||
const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
||||
|
@ -27,4 +29,5 @@ typedef unsigned long int glBufferIndex;
|
|||
const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
|
||||
|
||||
const double SIXTY_FPS_IN_MILLISECONDS = 1000.0/60;
|
||||
const double VIEW_CULLING_RATE_IN_MILLISECONDS = 1000.0; // once a second is fine
|
||||
#endif
|
||||
|
|
|
@ -20,29 +20,41 @@ using voxels_lib::printLog;
|
|||
// using voxels_lib::printLog;
|
||||
|
||||
VoxelNode::VoxelNode() {
|
||||
octalCode = NULL;
|
||||
unsigned char* rootCode = new unsigned char[1];
|
||||
*rootCode = 0;
|
||||
init(rootCode);
|
||||
}
|
||||
|
||||
VoxelNode::VoxelNode(unsigned char * octalCode) {
|
||||
init(octalCode);
|
||||
}
|
||||
|
||||
void VoxelNode::init(unsigned char * octalCode) {
|
||||
_octalCode = octalCode;
|
||||
|
||||
#ifdef HAS_FALSE_COLOR
|
||||
_falseColored = false; // assume true color
|
||||
#endif
|
||||
|
||||
// default pointers to child nodes to NULL
|
||||
for (int i = 0; i < 8; i++) {
|
||||
children[i] = NULL;
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
_children[i] = NULL;
|
||||
}
|
||||
|
||||
_glBufferIndex = GLBUFFER_INDEX_UNKNOWN;
|
||||
_isDirty = true;
|
||||
_shouldRender = false;
|
||||
|
||||
calculateAABox();
|
||||
}
|
||||
|
||||
VoxelNode::~VoxelNode() {
|
||||
delete[] octalCode;
|
||||
delete[] _octalCode;
|
||||
|
||||
// delete all of this node's children
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (children[i]) {
|
||||
delete children[i];
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
if (_children[i]) {
|
||||
delete _children[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,33 +67,47 @@ void VoxelNode::setShouldRender(bool shouldRender) {
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelNode::getAABox(AABox& box) const {
|
||||
void VoxelNode::calculateAABox() {
|
||||
|
||||
glm::vec3 corner;
|
||||
glm::vec3 size;
|
||||
|
||||
// copy corner into box
|
||||
copyFirstVertexForCode(octalCode,(float*)&corner);
|
||||
copyFirstVertexForCode(_octalCode,(float*)&corner);
|
||||
|
||||
// this tells you the "size" of the voxel
|
||||
float voxelScale = 1 / powf(2, *octalCode);
|
||||
float voxelScale = 1 / powf(2, *_octalCode);
|
||||
size = glm::vec3(voxelScale,voxelScale,voxelScale);
|
||||
|
||||
box.setBox(corner,size);
|
||||
_box.setBox(corner,size);
|
||||
}
|
||||
|
||||
void VoxelNode::deleteChildAtIndex(int childIndex) {
|
||||
if (_children[childIndex]) {
|
||||
delete _children[childIndex];
|
||||
_children[childIndex] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// does not delete the node!
|
||||
VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) {
|
||||
VoxelNode* returnedChild = _children[childIndex];
|
||||
if (_children[childIndex]) {
|
||||
_children[childIndex] = NULL;
|
||||
}
|
||||
return returnedChild;
|
||||
}
|
||||
|
||||
void VoxelNode::addChildAtIndex(int childIndex) {
|
||||
if (!children[childIndex]) {
|
||||
children[childIndex] = new VoxelNode();
|
||||
if (!_children[childIndex]) {
|
||||
_children[childIndex] = new VoxelNode(childOctalCode(_octalCode, childIndex));
|
||||
|
||||
// XXXBHG - When the node is constructed, it should be cleanly set up as
|
||||
// true colored, but for some reason, not so much. I've added a a basecamp
|
||||
// to-do to research this. But for now we'll use belt and suspenders and set
|
||||
// it to not-false-colored here!
|
||||
children[childIndex]->setFalseColored(false);
|
||||
_children[childIndex]->setFalseColored(false);
|
||||
|
||||
// give this child its octal code
|
||||
children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
@ -89,10 +115,10 @@ void VoxelNode::addChildAtIndex(int childIndex) {
|
|||
// will average the child colors...
|
||||
void VoxelNode::setColorFromAverageOfChildren() {
|
||||
int colorArray[4] = {0,0,0,0};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (children[i] != NULL && children[i]->isColored()) {
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
if (_children[i] && _children[i]->isColored()) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
colorArray[j] += children[i]->getTrueColor()[j]; // color averaging should always be based on true colors
|
||||
colorArray[j] += _children[i]->getTrueColor()[j]; // color averaging should always be based on true colors
|
||||
}
|
||||
colorArray[3]++;
|
||||
}
|
||||
|
@ -168,19 +194,19 @@ bool VoxelNode::collapseIdenticalLeaves() {
|
|||
// scan children, verify that they are ALL present and accounted for
|
||||
bool allChildrenMatch = true; // assume the best (ottimista)
|
||||
int red,green,blue;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
// if no child, or child doesn't have a color
|
||||
if (children[i] == NULL || !children[i]->isColored()) {
|
||||
if (!_children[i] || !_children[i]->isColored()) {
|
||||
allChildrenMatch=false;
|
||||
//printLog("SADNESS child missing or not colored! i=%d\n",i);
|
||||
break;
|
||||
} else {
|
||||
if (i==0) {
|
||||
red = children[i]->getColor()[0];
|
||||
green = children[i]->getColor()[1];
|
||||
blue = children[i]->getColor()[2];
|
||||
} else if (red != children[i]->getColor()[0] ||
|
||||
green != children[i]->getColor()[1] || blue != children[i]->getColor()[2]) {
|
||||
red = _children[i]->getColor()[0];
|
||||
green = _children[i]->getColor()[1];
|
||||
blue = _children[i]->getColor()[2];
|
||||
} else if (red != _children[i]->getColor()[0] ||
|
||||
green != _children[i]->getColor()[1] || blue != _children[i]->getColor()[2]) {
|
||||
allChildrenMatch=false;
|
||||
break;
|
||||
}
|
||||
|
@ -190,9 +216,9 @@ bool VoxelNode::collapseIdenticalLeaves() {
|
|||
|
||||
if (allChildrenMatch) {
|
||||
//printLog("allChildrenMatch: pruning tree\n");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
delete children[i]; // delete all the child nodes
|
||||
children[i]=NULL; // set it to NULL
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
delete _children[i]; // delete all the child nodes
|
||||
_children[i]=NULL; // set it to NULL
|
||||
}
|
||||
nodeColor collapsedColor;
|
||||
collapsedColor[0]=red;
|
||||
|
@ -215,8 +241,8 @@ void VoxelNode::setRandomColor(int minimumBrightness) {
|
|||
}
|
||||
|
||||
bool VoxelNode::isLeaf() const {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (children[i]) {
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
if (_children[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -224,27 +250,22 @@ bool VoxelNode::isLeaf() const {
|
|||
}
|
||||
|
||||
void VoxelNode::printDebugDetails(const char* label) const {
|
||||
AABox box;
|
||||
getAABox(box);
|
||||
printLog("%s - Voxel at corner=(%f,%f,%f) size=%f octcode=", label,
|
||||
box.getCorner().x, box.getCorner().y, box.getCorner().z, box.getSize().x);
|
||||
printOctalCode(octalCode);
|
||||
_box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getSize().x);
|
||||
printOctalCode(_octalCode);
|
||||
}
|
||||
|
||||
bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const {
|
||||
AABox box;
|
||||
getAABox(box);
|
||||
AABox box = _box; // use temporary box so we can scale it
|
||||
box.scale(TREE_SCALE);
|
||||
bool inView = (ViewFrustum::OUTSIDE != viewFrustum.boxInFrustum(box));
|
||||
return inView;
|
||||
}
|
||||
|
||||
float VoxelNode::distanceToCamera(const ViewFrustum& viewFrustum) const {
|
||||
AABox box;
|
||||
getAABox(box);
|
||||
box.scale(TREE_SCALE);
|
||||
float distanceToVoxelCenter = sqrtf(powf(viewFrustum.getPosition().x - (box.getCorner().x + box.getSize().x), 2) +
|
||||
powf(viewFrustum.getPosition().y - (box.getCorner().y + box.getSize().y), 2) +
|
||||
powf(viewFrustum.getPosition().z - (box.getCorner().z + box.getSize().z), 2));
|
||||
glm::vec3 center = _box.getCenter() * (float)TREE_SCALE;
|
||||
float distanceToVoxelCenter = sqrtf(powf(viewFrustum.getPosition().x - center.x, 2) +
|
||||
powf(viewFrustum.getPosition().y - center.y, 2) +
|
||||
powf(viewFrustum.getPosition().z - center.z, 2));
|
||||
return distanceToVoxelCenter;
|
||||
}
|
||||
|
|
|
@ -27,23 +27,38 @@ private:
|
|||
glBufferIndex _glBufferIndex;
|
||||
bool _isDirty;
|
||||
bool _shouldRender;
|
||||
AABox _box;
|
||||
unsigned char* _octalCode;
|
||||
VoxelNode* _children[8];
|
||||
|
||||
void calculateAABox();
|
||||
|
||||
void init(unsigned char * octalCode);
|
||||
|
||||
public:
|
||||
VoxelNode();
|
||||
VoxelNode(); // root node constructor
|
||||
VoxelNode(unsigned char * octalCode); // regular constructor
|
||||
~VoxelNode();
|
||||
|
||||
unsigned char* getOctalCode() const { return _octalCode; };
|
||||
VoxelNode* getChildAtIndex(int i) const { return _children[i]; };
|
||||
void deleteChildAtIndex(int childIndex);
|
||||
VoxelNode* removeChildAtIndex(int childIndex);
|
||||
void addChildAtIndex(int childIndex);
|
||||
void setColorFromAverageOfChildren();
|
||||
void setRandomColor(int minimumBrightness);
|
||||
bool collapseIdenticalLeaves();
|
||||
|
||||
unsigned char *octalCode;
|
||||
VoxelNode *children[8];
|
||||
|
||||
const AABox& getAABox() const { return _box; };
|
||||
const glm::vec3& getCenter() const { return _box.getCenter(); };
|
||||
const glm::vec3& getCorner() const { return _box.getCorner(); };
|
||||
float getScale() const { return _box.getSize().x; /* voxelScale = (1 / powf(2, *node->getOctalCode())); */ };
|
||||
int getLevel() const { return *_octalCode + 1; /* one based or zero based? */ };
|
||||
|
||||
bool isColored() const { return (_trueColor[3]==1); };
|
||||
bool isInView(const ViewFrustum& viewFrustum) const;
|
||||
float distanceToCamera(const ViewFrustum& viewFrustum) const;
|
||||
bool isLeaf() const;
|
||||
void getAABox(AABox& box) const;
|
||||
void printDebugDetails(const char* label) const;
|
||||
bool isDirty() const { return _isDirty; };
|
||||
void clearDirtyBit() { _isDirty = false; };
|
||||
|
|
|
@ -32,18 +32,12 @@ void VoxelNodeBag::insert(VoxelNode* node) {
|
|||
// Note: change this to binary search... instead of linear!
|
||||
int insertAt = _elementsInUse;
|
||||
for (int i = 0; i < _elementsInUse; i++) {
|
||||
|
||||
// compare the newNode to the elements already in the bag
|
||||
OctalCodeComparison comparison = compareOctalCodes(_bagElements[i]->octalCode, node->octalCode);
|
||||
|
||||
// If we found a code in the bag that matches, then just return, since the element is already in the bag.
|
||||
if (comparison == EXACT_MATCH) {
|
||||
// just compare the pointers... that's good enough
|
||||
if (_bagElements[i] == node) {
|
||||
return; // exit early!!
|
||||
}
|
||||
}
|
||||
|
||||
// if we found a node "greater than" the inserted node, then
|
||||
// we want to insert our node here.
|
||||
if (comparison == GREATER_THAN) {
|
||||
if (_bagElements[i] > node) {
|
||||
insertAt = i;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -37,17 +37,14 @@ VoxelTree::VoxelTree() :
|
|||
voxelsColoredStats(100),
|
||||
voxelsBytesReadStats(100),
|
||||
_isDirty(true) {
|
||||
|
||||
rootNode = new VoxelNode();
|
||||
rootNode->octalCode = new unsigned char[1];
|
||||
*rootNode->octalCode = 0;
|
||||
}
|
||||
|
||||
VoxelTree::~VoxelTree() {
|
||||
// delete the children of the root node
|
||||
// this recursively deletes the tree
|
||||
for (int i = 0; i < 8; i++) {
|
||||
delete rootNode->children[i];
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
delete rootNode->getChildAtIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,8 +57,8 @@ void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, vo
|
|||
// Recurses voxel node with an operation function
|
||||
void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData) {
|
||||
if (operation(node, extraData)) {
|
||||
for (int i = 0; i < sizeof(node->children) / sizeof(node->children[0]); i++) {
|
||||
VoxelNode* child = node->children[i];
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
VoxelNode* child = node->getChildAtIndex(i);
|
||||
if (child) {
|
||||
recurseNodeWithOperation(child, operation, extraData);
|
||||
}
|
||||
|
@ -72,11 +69,11 @@ void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperati
|
|||
VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode) const {
|
||||
// find the appropriate branch index based on this ancestorNode
|
||||
if (*needleCode > 0) {
|
||||
int branchForNeedle = branchIndexWithDescendant(ancestorNode->octalCode, needleCode);
|
||||
VoxelNode *childNode = ancestorNode->children[branchForNeedle];
|
||||
int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode);
|
||||
VoxelNode *childNode = ancestorNode->getChildAtIndex(branchForNeedle);
|
||||
|
||||
if (childNode != NULL) {
|
||||
if (*childNode->octalCode == *needleCode) {
|
||||
if (childNode) {
|
||||
if (*childNode->getOctalCode() == *needleCode) {
|
||||
|
||||
// If the caller asked for the parent, then give them that too...
|
||||
if (parentOfFoundNode) {
|
||||
|
@ -101,34 +98,31 @@ VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char *
|
|||
// returns the node created!
|
||||
VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char* codeToReach) {
|
||||
|
||||
int indexOfNewChild = branchIndexWithDescendant(lastParentNode->octalCode, codeToReach);
|
||||
int indexOfNewChild = branchIndexWithDescendant(lastParentNode->getOctalCode(), codeToReach);
|
||||
|
||||
// we could be coming down a branch that was already created, so don't stomp on it.
|
||||
if (lastParentNode->children[indexOfNewChild] == NULL) {
|
||||
if (!lastParentNode->getChildAtIndex(indexOfNewChild)) {
|
||||
lastParentNode->addChildAtIndex(indexOfNewChild);
|
||||
}
|
||||
|
||||
// This works because we know we traversed down the same tree so if the length is the same, then the whole code is the same
|
||||
if (*lastParentNode->children[indexOfNewChild]->octalCode == *codeToReach) {
|
||||
return lastParentNode->children[indexOfNewChild];
|
||||
if (*lastParentNode->getChildAtIndex(indexOfNewChild)->getOctalCode() == *codeToReach) {
|
||||
return lastParentNode->getChildAtIndex(indexOfNewChild);
|
||||
} else {
|
||||
return createMissingNode(lastParentNode->children[indexOfNewChild], codeToReach);
|
||||
return createMissingNode(lastParentNode->getChildAtIndex(indexOfNewChild), codeToReach);
|
||||
}
|
||||
}
|
||||
|
||||
// BHG Notes: We appear to call this function for every Voxel Node getting created.
|
||||
// This is recursive in nature. So, for example, if we are given an octal code for
|
||||
// a 1/256th size voxel, we appear to call this function 8 times. Maybe??
|
||||
int VoxelTree::readNodeData(VoxelNode* destinationNode,
|
||||
unsigned char* nodeData,
|
||||
int bytesLeftToRead) {
|
||||
// instantiate variable for bytes already read
|
||||
int bytesRead = 1;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
// check the colors mask to see if we have a child to color in
|
||||
if (oneAtBit(*nodeData, i)) {
|
||||
// create the child if it doesn't exist
|
||||
if (!destinationNode->children[i]) {
|
||||
if (!destinationNode->getChildAtIndex(i)) {
|
||||
destinationNode->addChildAtIndex(i);
|
||||
if (destinationNode->isDirty()) {
|
||||
_isDirty = true;
|
||||
|
@ -142,9 +136,9 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode,
|
|||
nodeColor newColor;
|
||||
memcpy(newColor, nodeData + bytesRead, 3);
|
||||
newColor[3] = 1;
|
||||
bool nodeWasDirty = destinationNode->children[i]->isDirty();
|
||||
destinationNode->children[i]->setColor(newColor);
|
||||
bool nodeIsDirty = destinationNode->children[i]->isDirty();
|
||||
bool nodeWasDirty = destinationNode->getChildAtIndex(i)->isDirty();
|
||||
destinationNode->getChildAtIndex(i)->setColor(newColor);
|
||||
bool nodeIsDirty = destinationNode->getChildAtIndex(i)->isDirty();
|
||||
if (nodeIsDirty) {
|
||||
_isDirty = true;
|
||||
}
|
||||
|
@ -164,11 +158,11 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode,
|
|||
int childIndex = 0;
|
||||
bytesRead++;
|
||||
|
||||
while (bytesLeftToRead - bytesRead > 0 && childIndex < 8) {
|
||||
while (bytesLeftToRead - bytesRead > 0 && childIndex < NUMBER_OF_CHILDREN) {
|
||||
// check the exists mask to see if we have a child to traverse into
|
||||
|
||||
if (oneAtBit(childMask, childIndex)) {
|
||||
if (!destinationNode->children[childIndex]) {
|
||||
if (!destinationNode->getChildAtIndex(childIndex)) {
|
||||
// add a child at that index, if it doesn't exist
|
||||
bool nodeWasDirty = destinationNode->isDirty();
|
||||
destinationNode->addChildAtIndex(childIndex);
|
||||
|
@ -184,7 +178,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode,
|
|||
}
|
||||
|
||||
// tell the child to read the subsequent data
|
||||
bytesRead += readNodeData(destinationNode->children[childIndex],
|
||||
bytesRead += readNodeData(destinationNode->getChildAtIndex(childIndex),
|
||||
nodeData + bytesRead,
|
||||
bytesLeftToRead - bytesRead);
|
||||
}
|
||||
|
@ -207,7 +201,7 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int
|
|||
|
||||
while (bitstreamAt < bitstream + bufferSizeBytes) {
|
||||
VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstreamAt, NULL);
|
||||
if (*bitstreamAt != *bitstreamRootNode->octalCode) {
|
||||
if (*bitstreamAt != *bitstreamRootNode->getOctalCode()) {
|
||||
// if the octal code returned is not on the same level as
|
||||
// the code being searched for, we have VoxelNodes to create
|
||||
|
||||
|
@ -251,12 +245,11 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) {
|
|||
// If the node exists...
|
||||
int lengthInBytes = bytesRequiredForCodeLength(*codeBuffer); // includes octet count, not color!
|
||||
|
||||
if (0 == memcmp(nodeToDelete->octalCode,codeBuffer,lengthInBytes)) {
|
||||
if (0 == memcmp(nodeToDelete->getOctalCode(),codeBuffer,lengthInBytes)) {
|
||||
if (parentNode) {
|
||||
int childIndex = branchIndexWithDescendant(parentNode->octalCode, codeBuffer);
|
||||
int childIndex = branchIndexWithDescendant(parentNode->getOctalCode(), codeBuffer);
|
||||
|
||||
delete parentNode->children[childIndex]; // delete the child nodes
|
||||
parentNode->children[childIndex] = NULL; // set it to NULL
|
||||
parentNode->deleteChildAtIndex(childIndex);
|
||||
|
||||
reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode
|
||||
_isDirty = true;
|
||||
|
@ -268,8 +261,6 @@ void VoxelTree::eraseAllVoxels() {
|
|||
// XXXBHG Hack attack - is there a better way to erase the voxel tree?
|
||||
delete rootNode; // this will recurse and delete all children
|
||||
rootNode = new VoxelNode();
|
||||
rootNode->octalCode = new unsigned char[1];
|
||||
*rootNode->octalCode = 0;
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
|
@ -277,7 +268,7 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) {
|
|||
VoxelNode* lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer, NULL);
|
||||
|
||||
// create the node if it does not exist
|
||||
if (*lastCreatedNode->octalCode != *codeColorBuffer) {
|
||||
if (*lastCreatedNode->getOctalCode() != *codeColorBuffer) {
|
||||
lastCreatedNode = createMissingNode(lastCreatedNode, codeColorBuffer);
|
||||
_isDirty = true;
|
||||
}
|
||||
|
@ -319,8 +310,8 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
|
|||
int colorMask = 0;
|
||||
|
||||
// create the color mask
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (startNode->children[i] != NULL && startNode->children[i]->isColored()) {
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
if (startNode->getChildAtIndex(i) && startNode->getChildAtIndex(i)->isColored()) {
|
||||
colorMask += (1 << (7 - i));
|
||||
}
|
||||
}
|
||||
|
@ -329,20 +320,20 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
|
|||
outputBits(colorMask);
|
||||
|
||||
// output the colors we have
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (startNode->children[j] != NULL && startNode->children[j]->isColored()) {
|
||||
for (int j = 0; j < NUMBER_OF_CHILDREN; j++) {
|
||||
if (startNode->getChildAtIndex(j) && startNode->getChildAtIndex(j)->isColored()) {
|
||||
printLog("color %d : ",j);
|
||||
for (int c = 0; c < 3; c++) {
|
||||
outputBits(startNode->children[j]->getTrueColor()[c],false);
|
||||
outputBits(startNode->getChildAtIndex(j)->getTrueColor()[c],false);
|
||||
}
|
||||
startNode->children[j]->printDebugDetails("");
|
||||
startNode->getChildAtIndex(j)->printDebugDetails("");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char childMask = 0;
|
||||
|
||||
for (int k = 0; k < 8; k++) {
|
||||
if (startNode->children[k] != NULL) {
|
||||
for (int k = 0; k < NUMBER_OF_CHILDREN; k++) {
|
||||
if (startNode->getChildAtIndex(k)) {
|
||||
childMask += (1 << (7 - k));
|
||||
}
|
||||
}
|
||||
|
@ -353,9 +344,9 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
|
|||
if (childMask > 0) {
|
||||
// ask children to recursively output their trees
|
||||
// if they aren't a leaf
|
||||
for (int l = 0; l < 8; l++) {
|
||||
if (startNode->children[l] != NULL) {
|
||||
printTreeForDebugging(startNode->children[l]);
|
||||
for (int l = 0; l < NUMBER_OF_CHILDREN; l++) {
|
||||
if (startNode->getChildAtIndex(l)) {
|
||||
printTreeForDebugging(startNode->getChildAtIndex(l));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -364,9 +355,9 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
|
|||
void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
|
||||
bool hasChildren = false;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (startNode->children[i] != NULL) {
|
||||
reaverageVoxelColors(startNode->children[i]);
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
if (startNode->getChildAtIndex(i)) {
|
||||
reaverageVoxelColors(startNode->getChildAtIndex(i));
|
||||
hasChildren = true;
|
||||
}
|
||||
}
|
||||
|
@ -396,8 +387,8 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
|||
file.get(octets);
|
||||
//printLog("octets=%d...\n",octets);
|
||||
totalBytesRead++;
|
||||
lengthInBytes = bytesRequiredForCodeLength(octets)-1; //(octets*3/8)+1;
|
||||
unsigned char * voxelData = new unsigned char[lengthInBytes+1+3];
|
||||
lengthInBytes = bytesRequiredForCodeLength(octets) - 1;
|
||||
unsigned char * voxelData = new unsigned char[lengthInBytes + 1 + 3];
|
||||
voxelData[0]=octets;
|
||||
char byte;
|
||||
|
||||
|
@ -437,7 +428,7 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
|||
VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const {
|
||||
unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0);
|
||||
VoxelNode* node = nodeForOctalCode(rootNode, octalCode, NULL);
|
||||
if (*node->octalCode != *octalCode) {
|
||||
if (*node->getOctalCode() != *octalCode) {
|
||||
node = NULL;
|
||||
}
|
||||
delete octalCode; // cleanup memory
|
||||
|
@ -465,28 +456,30 @@ void VoxelTree::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, r
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) {
|
||||
void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float voxelSize,
|
||||
bool solid, bool wantColorRandomizer, bool debug) {
|
||||
|
||||
// About the color of the sphere... we're going to make this sphere be a gradient
|
||||
// between two RGB colors. We will do the gradient along the phi spectrum
|
||||
unsigned char dominantColor1 = randIntInRange(1,3); //1=r, 2=g, 3=b dominant
|
||||
unsigned char dominantColor2 = randIntInRange(1,3);
|
||||
unsigned char dominantColor1 = randIntInRange(1, 3); //1=r, 2=g, 3=b dominant
|
||||
unsigned char dominantColor2 = randIntInRange(1, 3);
|
||||
|
||||
if (dominantColor1==dominantColor2) {
|
||||
dominantColor2 = dominantColor1+1%3;
|
||||
if (dominantColor1 == dominantColor2) {
|
||||
dominantColor2 = dominantColor1 + 1 % 3;
|
||||
}
|
||||
|
||||
unsigned char r1 = (dominantColor1==1)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char g1 = (dominantColor1==2)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char b1 = (dominantColor1==3)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char r2 = (dominantColor2==1)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char g2 = (dominantColor2==2)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char b2 = (dominantColor2==3)?randIntInRange(200,255):randIntInRange(40,100);
|
||||
unsigned char r1 = (dominantColor1 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100);
|
||||
unsigned char g1 = (dominantColor1 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100);
|
||||
unsigned char b1 = (dominantColor1 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100);
|
||||
unsigned char r2 = (dominantColor2 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100);
|
||||
unsigned char g2 = (dominantColor2 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100);
|
||||
unsigned char b2 = (dominantColor2 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100);
|
||||
|
||||
// We initialize our rgb to be either "grey" in case of randomized surface, or
|
||||
// the average of the gradient, in the case of the gradient sphere.
|
||||
unsigned char red = wantColorRandomizer ? 128 : (r1+r2)/2; // average of the colors
|
||||
unsigned char green = wantColorRandomizer ? 128 : (g1+g2)/2;
|
||||
unsigned char blue = wantColorRandomizer ? 128 : (b1+b2)/2;
|
||||
unsigned char red = wantColorRandomizer ? 128 : (r1 + r2) / 2; // average of the colors
|
||||
unsigned char green = wantColorRandomizer ? 128 : (g1 + g2) / 2;
|
||||
unsigned char blue = wantColorRandomizer ? 128 : (b1 + b2) / 2;
|
||||
|
||||
// Psuedocode for creating a sphere:
|
||||
//
|
||||
|
@ -495,50 +488,54 @@ void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool
|
|||
// x = xc+r*cos(theta)*sin(phi)
|
||||
// y = yc+r*sin(theta)*sin(phi)
|
||||
// z = zc+r*cos(phi)
|
||||
|
||||
int t=0; // total points
|
||||
|
||||
// We want to make sure that as we "sweep" through our angles we use a delta angle that's small enough to not skip any
|
||||
// voxels we can calculate theta from our desired arc length
|
||||
// lenArc = ndeg/360deg * 2pi*R ---> lenArc = theta/2pi * 2pi*R
|
||||
// lenArc = theta*R ---> theta = lenArc/R ---> theta = g/r
|
||||
float angleDelta = (s/r);
|
||||
|
||||
// assume solid for now
|
||||
float ri = 0.0;
|
||||
float thisRadius = 0.0;
|
||||
float thisVoxelSize = radius / 4.0f;
|
||||
|
||||
if (!solid) {
|
||||
ri=r; // just the outer surface
|
||||
thisRadius = radius; // just the outer surface
|
||||
thisVoxelSize = voxelSize;
|
||||
}
|
||||
|
||||
// If you also iterate form the interior of the sphere to the radius, makeing
|
||||
// larger and larger sphere's you'd end up with a solid sphere. And lots of voxels!
|
||||
for (; ri <= (r+(s/2.0)); ri+=s) {
|
||||
//printLog("radius: ri=%f ri+s=%f (r+(s/2.0))=%f\n",ri,ri+s,(r+(s/2.0)));
|
||||
for (float theta=0.0; theta <= 2*M_PI; theta += angleDelta) {
|
||||
// larger and larger sphere'voxelSize you'd end up with a solid sphere. And lots of voxels!
|
||||
while (thisRadius <= (radius + (voxelSize / 2.0))) {
|
||||
if (debug) {
|
||||
printLog("radius: thisRadius=%f thisVoxelSize=%f thisRadius+thisVoxelSize=%f (radius+(voxelSize/2.0))=%f\n",
|
||||
thisRadius, thisVoxelSize, thisRadius+thisVoxelSize, (radius + (voxelSize / 2.0)));
|
||||
}
|
||||
// We want to make sure that as we "sweep" through our angles we use a delta angle that voxelSize
|
||||
// small enough to not skip any voxels we can calculate theta from our desired arc length
|
||||
// lenArc = ndeg/360deg * 2pi*R ---> lenArc = theta/2pi * 2pi*R
|
||||
// lenArc = theta*R ---> theta = lenArc/R ---> theta = g/r
|
||||
float angleDelta = (thisVoxelSize / thisRadius);
|
||||
|
||||
for (float theta=0.0; theta <= 2 * M_PI; theta += angleDelta) {
|
||||
for (float phi=0.0; phi <= M_PI; phi += angleDelta) {
|
||||
t++; // total voxels
|
||||
float x = xc+ri*cos(theta)*sin(phi);
|
||||
float y = yc+ri*sin(theta)*sin(phi);
|
||||
float z = zc+ri*cos(phi);
|
||||
float x = xc + thisRadius * cos(theta) * sin(phi);
|
||||
float y = yc + thisRadius * sin(theta) * sin(phi);
|
||||
float z = zc + thisRadius * cos(phi);
|
||||
|
||||
// gradient color data
|
||||
float gradient = (phi/M_PI);
|
||||
float gradient = (phi / M_PI);
|
||||
|
||||
// only use our actual desired color on the outer edge, otherwise
|
||||
// use our "average" color
|
||||
if (ri+(s*2.0)>=r) {
|
||||
//printLog("painting candy shell radius: ri=%f r=%f\n",ri,r);
|
||||
red = wantColorRandomizer ? randomColorValue(165) : r1+((r2-r1)*gradient);
|
||||
green = wantColorRandomizer ? randomColorValue(165) : g1+((g2-g1)*gradient);
|
||||
blue = wantColorRandomizer ? randomColorValue(165) : b1+((b2-b1)*gradient);
|
||||
if (thisRadius + (voxelSize * 2.0) >= radius) {
|
||||
//printLog("painting candy shell radius: thisRadius=%f radius=%f\n",thisRadius,radius);
|
||||
red = wantColorRandomizer ? randomColorValue(165) : r1 + ((r2 - r1) * gradient);
|
||||
green = wantColorRandomizer ? randomColorValue(165) : g1 + ((g2 - g1) * gradient);
|
||||
blue = wantColorRandomizer ? randomColorValue(165) : b1 + ((b2 - b1) * gradient);
|
||||
}
|
||||
|
||||
unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue);
|
||||
unsigned char* voxelData = pointToVoxel(x, y, z, thisVoxelSize, red, green, blue);
|
||||
this->readCodeColorBufferToTree(voxelData);
|
||||
delete voxelData;
|
||||
}
|
||||
}
|
||||
thisRadius += thisVoxelSize;
|
||||
thisVoxelSize = std::max(voxelSize, thisVoxelSize / 2.0f);
|
||||
}
|
||||
this->reaverageVoxelColors(this->rootNode);
|
||||
}
|
||||
|
@ -564,8 +561,7 @@ public:
|
|||
|
||||
bool findRayOperation(VoxelNode* node, void* extraData) {
|
||||
RayArgs* args = static_cast<RayArgs*>(extraData);
|
||||
AABox box;
|
||||
node->getAABox(box);
|
||||
AABox box = node->getAABox();
|
||||
float distance;
|
||||
if (!box.findRayIntersection(args->origin, args->direction, distance)) {
|
||||
return false;
|
||||
|
@ -610,22 +606,20 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe
|
|||
int thisLevel = currentSearchLevel;
|
||||
int maxChildLevel = thisLevel;
|
||||
|
||||
const int MAX_CHILDREN = 8;
|
||||
VoxelNode* inViewChildren[MAX_CHILDREN];
|
||||
float distancesToChildren[MAX_CHILDREN];
|
||||
int positionOfChildren[MAX_CHILDREN];
|
||||
VoxelNode* inViewChildren[NUMBER_OF_CHILDREN];
|
||||
float distancesToChildren[NUMBER_OF_CHILDREN];
|
||||
int positionOfChildren[NUMBER_OF_CHILDREN];
|
||||
int inViewCount = 0;
|
||||
int inViewNotLeafCount = 0;
|
||||
int inViewWithColorCount = 0;
|
||||
|
||||
// for each child node, check to see if they exist, are colored, and in view, and if so
|
||||
// add them to our distance ordered array of children
|
||||
for (int i = 0; i < MAX_CHILDREN; i++) {
|
||||
VoxelNode* childNode = node->children[i];
|
||||
bool childExists = (childNode != NULL);
|
||||
bool childIsColored = (childExists && childNode->isColored());
|
||||
bool childIsInView = (childExists && childNode->isInView(viewFrustum));
|
||||
bool childIsLeaf = (childExists && childNode->isLeaf());
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
VoxelNode* childNode = node->getChildAtIndex(i);
|
||||
bool childIsColored = (childNode && childNode->isColored());
|
||||
bool childIsInView = (childNode && childNode->isInView(viewFrustum));
|
||||
bool childIsLeaf = (childNode && childNode->isLeaf());
|
||||
|
||||
if (childIsInView) {
|
||||
|
||||
|
@ -641,10 +635,10 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe
|
|||
|
||||
float distance = childNode->distanceToCamera(viewFrustum);
|
||||
|
||||
if (distance < boundaryDistanceForRenderLevel(*childNode->octalCode + 1)) {
|
||||
if (distance < boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1)) {
|
||||
inViewCount = insertIntoSortedArrays((void*)childNode, distance, i,
|
||||
(void**)&inViewChildren, (float*)&distancesToChildren,
|
||||
(int*)&positionOfChildren, inViewCount, MAX_CHILDREN);
|
||||
(int*)&positionOfChildren, inViewCount, NUMBER_OF_CHILDREN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -682,8 +676,8 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned
|
|||
}
|
||||
|
||||
// write the octal code
|
||||
int codeLength = bytesRequiredForCodeLength(*node->octalCode);
|
||||
memcpy(outputBuffer,node->octalCode,codeLength);
|
||||
int codeLength = bytesRequiredForCodeLength(*node->getOctalCode());
|
||||
memcpy(outputBuffer,node->getOctalCode(),codeLength);
|
||||
|
||||
outputBuffer += codeLength; // move the pointer
|
||||
bytesWritten += codeLength; // keep track of byte count
|
||||
|
@ -729,7 +723,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
|
|||
// caller can pass NULL as viewFrustum if they want everything
|
||||
if (viewFrustum) {
|
||||
float distance = node->distanceToCamera(*viewFrustum);
|
||||
float boundaryDistance = boundaryDistanceForRenderLevel(*node->octalCode + 1);
|
||||
float boundaryDistance = boundaryDistanceForRenderLevel(*node->getOctalCode() + 1);
|
||||
|
||||
// If we're too far away for our render level, then just return
|
||||
if (distance >= boundaryDistance) {
|
||||
|
@ -747,14 +741,13 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
|
|||
bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more!
|
||||
|
||||
// At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level
|
||||
// is 1 byte for child colors + 3*8 bytes for the actual colors + 1 byte for child trees. There could be sub trees
|
||||
// is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees. There could be sub trees
|
||||
// below this point, which might take many more bytes, but that's ok, because we can always mark our subtrees as
|
||||
// not existing and stop the packet at this point, then start up with a new packet for the remaining sub trees.
|
||||
const int CHILD_COLOR_MASK_BYTES = 1;
|
||||
const int MAX_CHILDREN = 8;
|
||||
const int BYTES_PER_COLOR = 3;
|
||||
const int CHILD_TREE_EXISTS_BYTES = 1;
|
||||
const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + MAX_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES;
|
||||
const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES;
|
||||
|
||||
// Make our local buffer large enough to handle writing at this level in case we need to.
|
||||
unsigned char thisLevelBuffer[MAX_LEVEL_BYTES];
|
||||
|
@ -768,14 +761,13 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
|
|||
|
||||
// for each child node, check to see if they exist, are colored, and in view, and if so
|
||||
// add them to our distance ordered array of children
|
||||
for (int i = 0; i < MAX_CHILDREN; i++) {
|
||||
VoxelNode* childNode = node->children[i];
|
||||
bool childExists = (childNode != NULL);
|
||||
bool childIsInView = (childExists && (!viewFrustum || childNode->isInView(*viewFrustum)));
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
VoxelNode* childNode = node->getChildAtIndex(i);
|
||||
bool childIsInView = (childNode && (!viewFrustum || childNode->isInView(*viewFrustum)));
|
||||
if (childIsInView) {
|
||||
// Before we determine consider this further, let's see if it's in our LOD scope...
|
||||
float distance = viewFrustum ? childNode->distanceToCamera(*viewFrustum) : 0;
|
||||
float boundaryDistance = viewFrustum ? boundaryDistanceForRenderLevel(*childNode->octalCode + 1) : 1;
|
||||
float boundaryDistance = viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1;
|
||||
|
||||
if (distance < boundaryDistance) {
|
||||
inViewCount++;
|
||||
|
@ -783,13 +775,13 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
|
|||
// track children in view as existing and not a leaf, if they're a leaf,
|
||||
// we don't care about recursing deeper on them, and we don't consider their
|
||||
// subtree to exist
|
||||
if (!(childExists && childNode->isLeaf())) {
|
||||
if (!(childNode && childNode->isLeaf())) {
|
||||
childrenExistBits += (1 << (7 - i));
|
||||
inViewNotLeafCount++;
|
||||
}
|
||||
|
||||
// track children with actual color
|
||||
if (childExists && childNode->isColored()) {
|
||||
if (childNode && childNode->isColored()) {
|
||||
childrenColoredBits += (1 << (7 - i));
|
||||
inViewWithColorCount++;
|
||||
}
|
||||
|
@ -801,9 +793,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
|
|||
bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count
|
||||
|
||||
// write the color data...
|
||||
for (int i = 0; i < MAX_CHILDREN; i++) {
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
if (oneAtBit(childrenColoredBits, i)) {
|
||||
memcpy(writeToThisLevelBuffer, &node->children[i]->getColor(), BYTES_PER_COLOR);
|
||||
memcpy(writeToThisLevelBuffer, &node->getChildAtIndex(i)->getColor(), BYTES_PER_COLOR);
|
||||
writeToThisLevelBuffer += BYTES_PER_COLOR; // move the pointer for color
|
||||
bytesAtThisLevel += BYTES_PER_COLOR; // keep track of byte count for color
|
||||
}
|
||||
|
@ -841,10 +833,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
|
|||
// we know the last thing we wrote to the outputBuffer was our childrenExistBits. Let's remember where that was!
|
||||
unsigned char* childExistsPlaceHolder = outputBuffer-sizeof(childrenExistBits);
|
||||
|
||||
for (int i = 0; i < MAX_CHILDREN; i++) {
|
||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||
|
||||
if (oneAtBit(childrenExistBits, i)) {
|
||||
VoxelNode* childNode = node->children[i];
|
||||
VoxelNode* childNode = node->getChildAtIndex(i);
|
||||
|
||||
int thisLevel = currentEncodeLevel;
|
||||
int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode,
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
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, bool wantColorRandomizer);
|
||||
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer, bool debug = false);
|
||||
|
||||
void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL);
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@ bool countVoxelsOperation(VoxelNode* node, void* extraData) {
|
|||
void addScene(VoxelTree * tree) {
|
||||
printf("adding scene...\n");
|
||||
|
||||
float voxelSize = 1.f/32;
|
||||
// We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so...
|
||||
float voxelSize = 0.5f / TREE_SCALE;
|
||||
|
||||
// Here's an example of how to create a voxel.
|
||||
printf("creating corner points...\n");
|
||||
|
@ -50,8 +51,6 @@ void addScene(VoxelTree * tree) {
|
|||
// Now some more examples... a little more complex
|
||||
printf("creating corner points...\n");
|
||||
tree->createVoxel(0 , 0 , 0 , voxelSize, 255, 255 ,255);
|
||||
|
||||
|
||||
tree->createVoxel(1.0 - voxelSize, 0 , 0 , voxelSize, 255, 0 ,0 );
|
||||
tree->createVoxel(0 , 1.0 - voxelSize, 0 , voxelSize, 0 , 255 ,0 );
|
||||
tree->createVoxel(0 , 0 , 1.0 - voxelSize, voxelSize, 0 , 0 ,255);
|
||||
|
@ -63,31 +62,32 @@ void addScene(VoxelTree * tree) {
|
|||
|
||||
// Now some more examples... creating some lines using the line primitive
|
||||
printf("creating voxel lines...\n");
|
||||
float lineVoxelSize = 0.99f/256;
|
||||
rgbColor red = {255,0,0};
|
||||
rgbColor green = {0,255,0};
|
||||
rgbColor blue = {0,0,255};
|
||||
// We want our line voxels to be about 1/32 meter high, and our TREE_SCALE is in meters, so...
|
||||
float lineVoxelSize = 1.f / (32 * TREE_SCALE);
|
||||
rgbColor red = {255, 0, 0};
|
||||
rgbColor green = {0, 255, 0};
|
||||
rgbColor blue = {0, 0, 255};
|
||||
tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), lineVoxelSize, blue);
|
||||
tree->createLine(glm::vec3(0, 0, 0), glm::vec3(1, 0, 0), lineVoxelSize, red);
|
||||
tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 1, 0), lineVoxelSize, green);
|
||||
printf("DONE creating lines...\n");
|
||||
|
||||
// Now some more examples... creating some spheres using the sphere primitive
|
||||
int sphereBaseSize = 512;
|
||||
printf("creating spheres...\n");
|
||||
tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, false);
|
||||
printf("one sphere added...\n");
|
||||
tree->createSphere(0.030625, 0.5, 0.5, (0.25-0.06125), (1.0 / (sphereBaseSize * 2)), true, true);
|
||||
// We want the smallest unit of our spheres to be about 1/16th of a meter tall
|
||||
float sphereVoxelSize = 1.f / (16 * TREE_SCALE);
|
||||
printf("creating spheres... sphereVoxelSize=%f\n",sphereVoxelSize);
|
||||
tree->createSphere(0.25, 0.5, 0.5, 0.5, sphereVoxelSize, true, false, true);
|
||||
printf("one sphere added... sphereVoxelSize=%f\n",sphereVoxelSize);
|
||||
|
||||
|
||||
printf("two spheres added...\n");
|
||||
tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true);
|
||||
printf("three spheres added...\n");
|
||||
tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, (1.0 / (sphereBaseSize * 2)), true, true);
|
||||
printf("four spheres added...\n");
|
||||
tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true);
|
||||
printf("five spheres added...\n");
|
||||
tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 0.125), (1.0 / (sphereBaseSize * 2)), true, true);
|
||||
tree->createSphere(0.030625, 0.5, 0.5, (0.25 - 0.06125), sphereVoxelSize, true, true);
|
||||
printf("two spheres added... sphereVoxelSize=%f\n",sphereVoxelSize);
|
||||
tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), sphereVoxelSize, true, true);
|
||||
printf("three spheres added... sphereVoxelSize=%f\n",sphereVoxelSize);
|
||||
tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, sphereVoxelSize, true, true);
|
||||
printf("four spheres added... sphereVoxelSize=%f\n",sphereVoxelSize);
|
||||
tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), sphereVoxelSize, true, true);
|
||||
printf("five spheres added... sphereVoxelSize=%f\n",sphereVoxelSize);
|
||||
tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 0.125), sphereVoxelSize, true, true);
|
||||
|
||||
float radius = 0.0125f;
|
||||
printf("6 spheres added...\n");
|
||||
|
@ -102,7 +102,6 @@ void addScene(VoxelTree * tree) {
|
|||
tree->createSphere(radius, 0.025, radius * 5.0f, 0.25, (1.0 / 4096), true, true);
|
||||
printf("11 spheres added...\n");
|
||||
printf("DONE creating spheres...\n");
|
||||
|
||||
// Here's an example of how to recurse the tree and do some operation on the nodes as you recurse them.
|
||||
// This one is really simple, it just couts them...
|
||||
// Look at the function countVoxelsOperation() for an example of how you could use this function
|
||||
|
|
|
@ -38,7 +38,7 @@ const float DEATH_STAR_RADIUS = 4.0;
|
|||
const float MAX_CUBE = 0.05f;
|
||||
|
||||
const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000;
|
||||
int PACKETS_PER_CLIENT_PER_INTERVAL = 20;
|
||||
int PACKETS_PER_CLIENT_PER_INTERVAL = 50;
|
||||
|
||||
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
|
||||
|
||||
|
@ -153,12 +153,8 @@ void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) {
|
|||
for (int i = 0; i < 8; i++) {
|
||||
if (true) {
|
||||
// create a new VoxelNode to put here
|
||||
currentRootNode->children[i] = new VoxelNode();
|
||||
|
||||
// give this child it's octal code
|
||||
currentRootNode->children[i]->octalCode = childOctalCode(currentRootNode->octalCode, i);
|
||||
|
||||
randomlyFillVoxelTree(levelsToGo - 1, currentRootNode->children[i]);
|
||||
currentRootNode->addChildAtIndex(i);
|
||||
randomlyFillVoxelTree(levelsToGo - 1, currentRootNode->getChildAtIndex(i));
|
||||
createdChildren = true;
|
||||
}
|
||||
}
|
||||
|
@ -551,12 +547,9 @@ int main(int argc, const char * argv[])
|
|||
// If we got a PACKET_HEADER_HEAD_DATA, then we're talking to an AGENT_TYPE_AVATAR, and we
|
||||
// need to make sure we have it in our agentList.
|
||||
if (packetData[0] == PACKET_HEADER_HEAD_DATA) {
|
||||
if (agentList->addOrUpdateAgent(&agentPublicAddress,
|
||||
&agentPublicAddress,
|
||||
AGENT_TYPE_AVATAR,
|
||||
agentList->getLastAgentId())) {
|
||||
agentList->increaseAgentId();
|
||||
}
|
||||
uint16_t agentID = 0;
|
||||
unpackAgentId(packetData + sizeof(PACKET_HEADER_HEAD_DATA), &agentID);
|
||||
agentList->addOrUpdateAgent(&agentPublicAddress, &agentPublicAddress, AGENT_TYPE_AVATAR, agentID);
|
||||
|
||||
agentList->updateAgentWithData(&agentPublicAddress, packetData, receivedBytes);
|
||||
}
|
||||
|
|