mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 14:59:47 +02:00
#19197 Create basic visual studio
This commit is contained in:
commit
622053b38c
22 changed files with 934 additions and 570 deletions
|
@ -37,6 +37,7 @@
|
|||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
|
||||
const int DOMAIN_LISTEN_PORT = 40102;
|
||||
unsigned char packetData[MAX_PACKET_SIZE];
|
||||
|
||||
|
@ -60,6 +61,21 @@ unsigned char * addAgentToBroadcastPacket(unsigned char *currentPosition, Agent
|
|||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
// If user asks to run in "local" mode then we do NOT replace the IP
|
||||
// with the EC2 IP. Otherwise, we will replace the IP like we used to
|
||||
// this allows developers to run a local domain without recompiling the
|
||||
// domain server
|
||||
bool useLocal = cmdOptionExists(argc, argv, "--local");
|
||||
if (useLocal) {
|
||||
printf("NOTE: Running in Local Mode!\n");
|
||||
} else {
|
||||
printf("--------------------------------------------------\n");
|
||||
printf("NOTE: Running in EC2 Mode. \n");
|
||||
printf("If you're a developer testing a local system, you\n");
|
||||
printf("probably want to include --local on command line.\n");
|
||||
printf("--------------------------------------------------\n");
|
||||
}
|
||||
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
ssize_t receivedBytes = 0;
|
||||
|
@ -90,7 +106,11 @@ int main(int argc, const char * argv[])
|
|||
// if it matches our local address we're on the same box
|
||||
// so hardcode the EC2 public address for now
|
||||
if (agentPublicAddress.sin_addr.s_addr == serverLocalAddress) {
|
||||
agentPublicAddress.sin_addr.s_addr = 895283510;
|
||||
// If we're not running "local" then we do replace the IP
|
||||
// with the EC2 IP. Otherwise, we use our normal public IP
|
||||
if (!useLocal) {
|
||||
agentPublicAddress.sin_addr.s_addr = 895283510; // local IP in this format...
|
||||
}
|
||||
}
|
||||
|
||||
if (agentList.addOrUpdateAgent((sockaddr *)&agentPublicAddress,
|
||||
|
|
|
@ -158,9 +158,6 @@ int audioCallback (const void *inputBuffer,
|
|||
currentPacketPtr += sizeof(float);
|
||||
}
|
||||
|
||||
// tell the mixer not to add additional attenuation to our source
|
||||
*(currentPacketPtr++) = 255;
|
||||
|
||||
// memcpy the corrected render yaw
|
||||
float correctedYaw = fmodf(data->linkedHead->getRenderYaw(), 360);
|
||||
|
||||
|
@ -177,35 +174,35 @@ int audioCallback (const void *inputBuffer,
|
|||
memcpy(currentPacketPtr, &correctedYaw, sizeof(float));
|
||||
currentPacketPtr += sizeof(float);
|
||||
|
||||
if (samplesLeftForWalk == 0) {
|
||||
sampleWalkPointer = walkingSoundArray;
|
||||
}
|
||||
|
||||
if (data->playWalkSound) {
|
||||
// if this boolean is true and we aren't currently playing the walk sound
|
||||
// set the number of samples left for walk
|
||||
samplesLeftForWalk = walkingSoundSamples;
|
||||
data->playWalkSound = false;
|
||||
}
|
||||
|
||||
if (samplesLeftForWalk > 0) {
|
||||
// we need to play part of the walking sound
|
||||
// so add it in
|
||||
int affectedSamples = std::min(samplesLeftForWalk, BUFFER_LENGTH_SAMPLES);
|
||||
for (int i = 0; i < affectedSamples; i++) {
|
||||
inputLeft[i] += *sampleWalkPointer;
|
||||
inputLeft[i] = std::max(inputLeft[i], std::numeric_limits<int16_t>::min());
|
||||
inputLeft[i] = std::min(inputLeft[i], std::numeric_limits<int16_t>::max());
|
||||
|
||||
sampleWalkPointer++;
|
||||
samplesLeftForWalk--;
|
||||
|
||||
if (sampleWalkPointer - walkingSoundArray > walkingSoundSamples) {
|
||||
sampleWalkPointer = walkingSoundArray;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// if (samplesLeftForWalk == 0) {
|
||||
// sampleWalkPointer = walkingSoundArray;
|
||||
// }
|
||||
//
|
||||
// if (data->playWalkSound) {
|
||||
// // if this boolean is true and we aren't currently playing the walk sound
|
||||
// // set the number of samples left for walk
|
||||
// samplesLeftForWalk = walkingSoundSamples;
|
||||
// data->playWalkSound = false;
|
||||
// }
|
||||
//
|
||||
// if (samplesLeftForWalk > 0) {
|
||||
// // we need to play part of the walking sound
|
||||
// // so add it in
|
||||
// int affectedSamples = std::min(samplesLeftForWalk, BUFFER_LENGTH_SAMPLES);
|
||||
// for (int i = 0; i < affectedSamples; i++) {
|
||||
// inputLeft[i] += *sampleWalkPointer;
|
||||
// inputLeft[i] = std::max(inputLeft[i], std::numeric_limits<int16_t>::min());
|
||||
// inputLeft[i] = std::min(inputLeft[i], std::numeric_limits<int16_t>::max());
|
||||
//
|
||||
// sampleWalkPointer++;
|
||||
// samplesLeftForWalk--;
|
||||
//
|
||||
// if (sampleWalkPointer - walkingSoundArray > walkingSoundSamples) {
|
||||
// sampleWalkPointer = walkingSoundArray;
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
||||
|
||||
// copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet
|
||||
|
@ -267,19 +264,19 @@ int audioCallback (const void *inputBuffer,
|
|||
}
|
||||
|
||||
// check if we have more than we need to play out
|
||||
int thresholdFrames = ceilf((PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) / (float)PACKET_LENGTH_SAMPLES);
|
||||
int thresholdSamples = thresholdFrames * PACKET_LENGTH_SAMPLES;
|
||||
|
||||
if (ringBuffer->diffLastWriteNextOutput() > thresholdSamples) {
|
||||
// we need to push the next output forwards
|
||||
int samplesToPush = ringBuffer->diffLastWriteNextOutput() - thresholdSamples;
|
||||
|
||||
if (ringBuffer->getNextOutput() + samplesToPush > ringBuffer->getBuffer()) {
|
||||
ringBuffer->setNextOutput(ringBuffer->getBuffer() + (samplesToPush - (ringBuffer->getBuffer() + RING_BUFFER_SAMPLES - ringBuffer->getNextOutput())));
|
||||
} else {
|
||||
ringBuffer->setNextOutput(ringBuffer->getNextOutput() + samplesToPush);
|
||||
}
|
||||
}
|
||||
// int thresholdFrames = ceilf((PACKET_LENGTH_SAMPLES + JITTER_BUFFER_SAMPLES) / (float)PACKET_LENGTH_SAMPLES);
|
||||
// int thresholdSamples = thresholdFrames * PACKET_LENGTH_SAMPLES;
|
||||
//
|
||||
// if (ringBuffer->diffLastWriteNextOutput() > thresholdSamples) {
|
||||
// // we need to push the next output forwards
|
||||
// int samplesToPush = ringBuffer->diffLastWriteNextOutput() - thresholdSamples;
|
||||
//
|
||||
// if (ringBuffer->getNextOutput() + samplesToPush > ringBuffer->getBuffer()) {
|
||||
// ringBuffer->setNextOutput(ringBuffer->getBuffer() + (samplesToPush - (ringBuffer->getBuffer() + RING_BUFFER_SAMPLES - ringBuffer->getNextOutput())));
|
||||
// } else {
|
||||
// ringBuffer->setNextOutput(ringBuffer->getNextOutput() + samplesToPush);
|
||||
// }
|
||||
// }
|
||||
|
||||
for (int s = 0; s < PACKET_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
||||
|
||||
|
|
|
@ -32,14 +32,12 @@ float browThickness = 0.16;
|
|||
|
||||
const float DECAY = 0.1;
|
||||
|
||||
char iris_texture_file[] = "images/green_eye.png";
|
||||
char iris_texture_file[] = "resources/images/green_eye.png";
|
||||
|
||||
vector<unsigned char> iris_texture;
|
||||
unsigned int iris_texture_width = 512;
|
||||
unsigned int iris_texture_height = 256;
|
||||
|
||||
GLUquadric *sphere = gluNewQuadric();
|
||||
|
||||
Head::Head()
|
||||
{
|
||||
position = glm::vec3(0,0,0);
|
||||
|
@ -80,6 +78,8 @@ Head::Head()
|
|||
browAudioLift = 0.0;
|
||||
noise = 0;
|
||||
|
||||
sphere = NULL;
|
||||
|
||||
hand = new Hand(glm::vec3(skinColor[0], skinColor[1], skinColor[2]));
|
||||
|
||||
if (iris_texture.size() == 0) {
|
||||
|
@ -135,12 +135,14 @@ Head::Head(const Head &otherHead) {
|
|||
browAudioLift = otherHead.browAudioLift;
|
||||
noise = otherHead.noise;
|
||||
|
||||
sphere = NULL;
|
||||
|
||||
Hand newHand = Hand(*otherHead.hand);
|
||||
hand = &newHand;
|
||||
}
|
||||
|
||||
Head::~Head() {
|
||||
if (sphere) {
|
||||
if (sphere != NULL) {
|
||||
gluDeleteQuadric(sphere);
|
||||
}
|
||||
}
|
||||
|
@ -454,7 +456,7 @@ void Head::render(int faceToFace, int isMine)
|
|||
glPopMatrix();
|
||||
|
||||
// Right Pupil
|
||||
if (!sphere) {
|
||||
if (sphere == NULL) {
|
||||
sphere = gluNewQuadric();
|
||||
gluQuadricTexture(sphere, GL_TRUE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
|
|
@ -130,6 +130,8 @@ class Head : public AgentData {
|
|||
int eyeContact;
|
||||
eyeContactTargets eyeContactTarget;
|
||||
|
||||
GLUquadric *sphere;
|
||||
|
||||
void readSensors();
|
||||
float renderYaw, renderPitch; // Pitch from view frustum when this is own head.
|
||||
|
||||
|
|
|
@ -15,9 +15,10 @@
|
|||
#include <fstream> // to load voxels from file
|
||||
#include <SharedUtil.h>
|
||||
#include <OctalCode.h>
|
||||
#include <pthread.h>
|
||||
#include "VoxelSystem.h"
|
||||
|
||||
const int MAX_VOXELS_PER_SYSTEM = 250000;
|
||||
const int MAX_VOXELS_PER_SYSTEM = 1500000; //250000;
|
||||
|
||||
const int VERTICES_PER_VOXEL = 8;
|
||||
const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
||||
|
@ -42,12 +43,20 @@ GLubyte identityIndices[] = { 0,1,2, 0,2,3,
|
|||
VoxelSystem::VoxelSystem() {
|
||||
voxelsRendered = 0;
|
||||
tree = new VoxelTree();
|
||||
pthread_mutex_init(&bufferWriteLock, NULL);
|
||||
}
|
||||
|
||||
VoxelSystem::~VoxelSystem() {
|
||||
delete[] verticesArray;
|
||||
delete[] colorsArray;
|
||||
delete[] readVerticesArray;
|
||||
delete[] writeVerticesArray;
|
||||
delete[] readColorsArray;
|
||||
delete[] writeColorsArray;
|
||||
delete tree;
|
||||
pthread_mutex_destroy(&bufferWriteLock);
|
||||
}
|
||||
|
||||
void VoxelSystem::setViewerHead(Head *newViewerHead) {
|
||||
viewerHead = newViewerHead;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -57,65 +66,11 @@ VoxelSystem::~VoxelSystem() {
|
|||
// colors are set randomly
|
||||
// Complaints: Brad :)
|
||||
// To Do: Need to add color data to the file.
|
||||
void VoxelSystem::loadVoxelsFile(char* fileName) {
|
||||
int vCount = 0;
|
||||
|
||||
std::ifstream file(fileName, std::ios::in|std::ios::binary);
|
||||
|
||||
char octets;
|
||||
unsigned int lengthInBytes;
|
||||
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
||||
|
||||
int totalBytesRead = 0;
|
||||
if(file.is_open())
|
||||
{
|
||||
bool bail = false;
|
||||
while (!file.eof() && !bail) {
|
||||
file.get(octets);
|
||||
totalBytesRead++;
|
||||
lengthInBytes = bytesRequiredForCodeLength(octets)-1; //(octets*3/8)+1;
|
||||
unsigned char * voxelData = new unsigned char[lengthInBytes+1+3];
|
||||
voxelData[0]=octets;
|
||||
char byte;
|
||||
|
||||
for (size_t i = 0; i < lengthInBytes; i++) {
|
||||
file.get(byte);
|
||||
totalBytesRead++;
|
||||
voxelData[i+1] = byte;
|
||||
}
|
||||
// read color data
|
||||
char red,green,blue;
|
||||
file.get(red);
|
||||
file.get(green);
|
||||
file.get(blue);
|
||||
|
||||
//printf("red:%d\n",red);
|
||||
//printf("green:%d\n",green);
|
||||
//printf("blue:%d\n",blue);
|
||||
vCount++;
|
||||
//printf("vCount:%d\n",vCount);
|
||||
|
||||
//randomColorValue(65);
|
||||
float rf = randFloatInRange(.5,1); // add a little bit of variance to colors so we can see the voxels
|
||||
voxelData[lengthInBytes+1] = red * rf;
|
||||
voxelData[lengthInBytes+2] = green * rf;
|
||||
voxelData[lengthInBytes+3] = blue * rf;
|
||||
|
||||
//printVoxelCode(voxelData);
|
||||
tree->readCodeColorBufferToTree(voxelData);
|
||||
delete voxelData;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
tree->loadVoxelsFile(fileName,wantColorRandomizer);
|
||||
|
||||
tree->pruneTree(tree->rootNode);
|
||||
|
||||
// reset the verticesEndPointer so we're writing to the beginning of the array
|
||||
verticesEndPointer = verticesArray;
|
||||
// call recursive function to populate in memory arrays
|
||||
// it will return the number of voxels added
|
||||
voxelsRendered = treeToArrays(tree->rootNode);
|
||||
// set the boolean if there are any voxels to be rendered so we re-fill the VBOs
|
||||
voxelsToRender = (voxelsRendered > 0);
|
||||
copyWrittenDataToReadArrays();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -125,107 +80,10 @@ void VoxelSystem::loadVoxelsFile(char* fileName) {
|
|||
// mechanism to tell the system to redraw it's arrays after voxels are done
|
||||
// being added. This is a concept mostly only understood by VoxelSystem.
|
||||
// Complaints: Brad :)
|
||||
void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid)
|
||||
{
|
||||
// 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 r1 = randomColorValue(165);
|
||||
unsigned char g1 = randomColorValue(165);
|
||||
unsigned char b1 = randomColorValue(165);
|
||||
unsigned char r2 = randomColorValue(65);
|
||||
unsigned char g2 = randomColorValue(65);
|
||||
unsigned char b2 = randomColorValue(65);
|
||||
|
||||
// we don't want them to match!!
|
||||
if (r1==r2 && g1==g2 && b1==b2)
|
||||
{
|
||||
r2=r1/2;
|
||||
g2=g1/2;
|
||||
b2=b1/2;
|
||||
}
|
||||
void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) {
|
||||
|
||||
/**
|
||||
std::cout << "creatSphere COLORS ";
|
||||
std::cout << " r1=" << (int)r1;
|
||||
std::cout << " g1=" << (int)g1;
|
||||
std::cout << " b1=" << (int)b1;
|
||||
std::cout << " r2=" << (int)r2;
|
||||
std::cout << " g2=" << (int)g2;
|
||||
std::cout << " b2=" << (int)b2;
|
||||
std::cout << std::endl;
|
||||
**/
|
||||
|
||||
// Psuedocode for creating a sphere:
|
||||
//
|
||||
// for (theta from 0 to 2pi):
|
||||
// for (phi from 0 to pi):
|
||||
// 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;
|
||||
if (!solid)
|
||||
{
|
||||
ri=r; // just the outer surface
|
||||
}
|
||||
// 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; ri+=s)
|
||||
{
|
||||
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+r*cos(theta)*sin(phi);
|
||||
float y = yc+r*sin(theta)*sin(phi);
|
||||
float z = zc+r*cos(phi);
|
||||
/*
|
||||
std::cout << " r=" << r;
|
||||
std::cout << " theta=" << theta;
|
||||
std::cout << " phi=" << phi;
|
||||
std::cout << " x=" << x;
|
||||
std::cout << " y=" << y;
|
||||
std::cout << " z=" << z;
|
||||
std::cout << " t=" << t;
|
||||
std::cout << std::endl;
|
||||
*/
|
||||
|
||||
// gradient color data
|
||||
float gradient = (phi/M_PI);
|
||||
unsigned char red = r1+((r2-r1)*gradient);
|
||||
unsigned char green = g1+((g2-g1)*gradient);
|
||||
unsigned char blue = b1+((b2-b1)*gradient);
|
||||
|
||||
unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue);
|
||||
tree->readCodeColorBufferToTree(voxelData);
|
||||
delete voxelData;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// reset the verticesEndPointer so we're writing to the beginning of the array
|
||||
verticesEndPointer = verticesArray;
|
||||
// call recursive function to populate in memory arrays
|
||||
// it will return the number of voxels added
|
||||
voxelsRendered = treeToArrays(tree->rootNode);
|
||||
// set the boolean if there are any voxels to be rendered so we re-fill the VBOs
|
||||
voxelsToRender = (voxelsRendered > 0);
|
||||
tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
||||
|
@ -233,32 +91,74 @@ void VoxelSystem::parseData(void *data, int size) {
|
|||
// output the bits received from the voxel server
|
||||
unsigned char *voxelData = (unsigned char *) data + 1;
|
||||
|
||||
printf("Received a packet of %d bytes from VS\n", size);
|
||||
|
||||
// ask the VoxelTree to read the bitstream into the tree
|
||||
tree->readBitstreamToTree(voxelData, size - 1);
|
||||
|
||||
// reset the verticesEndPointer so we're writing to the beginning of the array
|
||||
verticesEndPointer = verticesArray;
|
||||
|
||||
// call recursive function to populate in memory arrays
|
||||
// it will return the number of voxels added
|
||||
voxelsRendered = treeToArrays(tree->rootNode);
|
||||
|
||||
// set the boolean if there are any voxels to be rendered so we re-fill the VBOs
|
||||
voxelsToRender = (voxelsRendered > 0);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
int VoxelSystem::treeToArrays(VoxelNode *currentNode) {
|
||||
void VoxelSystem::setupNewVoxelsForDrawing() {
|
||||
// reset the verticesEndPointer so we're writing to the beginning of the array
|
||||
writeVerticesEndPointer = writeVerticesArray;
|
||||
// call recursive function to populate in memory arrays
|
||||
// it will return the number of voxels added
|
||||
float treeRoot[3] = {0,0,0};
|
||||
voxelsRendered = treeToArrays(tree->rootNode, treeRoot);
|
||||
|
||||
// copy the newly written data to the arrays designated for reading
|
||||
copyWrittenDataToReadArrays();
|
||||
}
|
||||
|
||||
void VoxelSystem::copyWrittenDataToReadArrays() {
|
||||
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
||||
pthread_mutex_lock(&bufferWriteLock);
|
||||
// store a pointer to the current end so it doesn't change during copy
|
||||
GLfloat *endOfCurrentVerticesData = writeVerticesEndPointer;
|
||||
// copy the vertices and colors
|
||||
memcpy(readVerticesArray, writeVerticesArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLfloat));
|
||||
memcpy(readColorsArray, writeColorsArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLubyte));
|
||||
|
||||
// set the read vertices end pointer to the correct spot so the GPU knows how much to pull
|
||||
readVerticesEndPointer = readVerticesArray + (endOfCurrentVerticesData - writeVerticesArray);
|
||||
pthread_mutex_unlock(&bufferWriteLock);
|
||||
}
|
||||
|
||||
int VoxelSystem::treeToArrays(VoxelNode *currentNode, float nodePosition[3]) {
|
||||
int voxelsAdded = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// check if there is a child here
|
||||
if (currentNode->children[i] != NULL) {
|
||||
voxelsAdded += treeToArrays(currentNode->children[i]);
|
||||
float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE);
|
||||
glm::vec3 viewerPosition = viewerHead->getPos();
|
||||
|
||||
float distanceToVoxelCenter = sqrtf(powf(viewerPosition[0] - nodePosition[0] - halfUnitForVoxel, 2) +
|
||||
powf(viewerPosition[1] - nodePosition[1] - halfUnitForVoxel, 2) +
|
||||
powf(viewerPosition[2] - nodePosition[2] - halfUnitForVoxel, 2));
|
||||
|
||||
if (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentNode->octalCode + 1)) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// check if there is a child here
|
||||
if (currentNode->children[i] != NULL) {
|
||||
|
||||
// calculate the child's position based on the parent position
|
||||
float childNodePosition[3];
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
childNodePosition[j] = nodePosition[j];
|
||||
|
||||
if (oneAtBit(branchIndexWithDescendant(currentNode->octalCode,
|
||||
currentNode->children[i]->octalCode),
|
||||
(7 - j))) {
|
||||
childNodePosition[j] -= (powf(0.5, *currentNode->children[i]->octalCode) * TREE_SCALE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if we didn't get any voxels added then we're a leaf
|
||||
// add our vertex and color information to the interleaved array
|
||||
if (voxelsAdded == 0 && currentNode->color[3] == 1) {
|
||||
|
@ -268,10 +168,10 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode) {
|
|||
// 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++ ) {
|
||||
*verticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||
*(colorsArray + (verticesEndPointer - verticesArray)) = currentNode->color[j % 3];
|
||||
*writeVerticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||
*(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->color[j % 3];
|
||||
|
||||
verticesEndPointer++;
|
||||
writeVerticesEndPointer++;
|
||||
}
|
||||
|
||||
voxelsAdded++;
|
||||
|
@ -289,8 +189,10 @@ VoxelSystem* VoxelSystem::clone() const {
|
|||
|
||||
void VoxelSystem::init() {
|
||||
// prep the data structures for incoming voxel data
|
||||
verticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
colorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
|
||||
GLuint *indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
|
||||
|
@ -321,7 +223,9 @@ void VoxelSystem::init() {
|
|||
// VBO for the indicesArray
|
||||
glGenBuffers(1, &vboIndicesID);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM, indicesArray, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM,
|
||||
indicesArray, GL_STATIC_DRAW);
|
||||
|
||||
// delete the indices array that is no longer needed
|
||||
delete[] indicesArray;
|
||||
|
@ -331,16 +235,24 @@ void VoxelSystem::render() {
|
|||
|
||||
glPushMatrix();
|
||||
|
||||
if (voxelsToRender) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, (verticesEndPointer - verticesArray) * sizeof(GLfloat), verticesArray);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, (verticesEndPointer - verticesArray) * sizeof(GLubyte), colorsArray);
|
||||
|
||||
voxelsToRender = false;
|
||||
|
||||
if (readVerticesEndPointer != readVerticesArray) {
|
||||
// try to lock on the buffer write
|
||||
// just avoid pulling new data if it is currently being written
|
||||
if (pthread_mutex_trylock(&bufferWriteLock) == 0) {
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLfloat), readVerticesArray);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLubyte), readColorsArray);
|
||||
|
||||
readVerticesEndPointer = readVerticesArray;
|
||||
|
||||
pthread_mutex_unlock(&bufferWriteLock);
|
||||
}
|
||||
}
|
||||
|
||||
// tell OpenGL where to find vertex and color information
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <UDPSocket.h>
|
||||
#include <AgentData.h>
|
||||
#include <VoxelTree.h>
|
||||
#include "Head.h"
|
||||
#include "Util.h"
|
||||
#include "world.h"
|
||||
|
||||
|
@ -33,20 +34,27 @@ public:
|
|||
void render();
|
||||
void setVoxelsRendered(int v) {voxelsRendered = v;};
|
||||
int getVoxelsRendered() {return voxelsRendered;};
|
||||
void loadVoxelsFile(char* fileName);
|
||||
void createSphere(float r,float xc, float yc, float zc, float s, bool solid);
|
||||
void setViewerHead(Head *newViewerHead);
|
||||
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
|
||||
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer);
|
||||
private:
|
||||
int voxelsRendered;
|
||||
Head *viewerHead;
|
||||
VoxelTree *tree;
|
||||
bool voxelsToRender;
|
||||
GLfloat *verticesArray;
|
||||
GLubyte *colorsArray;
|
||||
GLfloat *verticesEndPointer;
|
||||
GLfloat *readVerticesArray;
|
||||
GLubyte *readColorsArray;
|
||||
GLfloat *readVerticesEndPointer;
|
||||
GLfloat *writeVerticesArray;
|
||||
GLubyte *writeColorsArray;
|
||||
GLfloat *writeVerticesEndPointer;
|
||||
GLuint vboVerticesID;
|
||||
GLuint vboColorsID;
|
||||
GLuint vboIndicesID;
|
||||
pthread_mutex_t bufferWriteLock;
|
||||
|
||||
int treeToArrays(VoxelNode *currentNode);
|
||||
int treeToArrays(VoxelNode *currentNode, float nodePosition[3]);
|
||||
void setupNewVoxelsForDrawing();
|
||||
void copyWrittenDataToReadArrays();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -81,6 +81,8 @@ int WIDTH = 1200;
|
|||
int HEIGHT = 800;
|
||||
int fullscreen = 0;
|
||||
|
||||
bool wantColorRandomizer = true; // for addSphere and load file
|
||||
|
||||
Oscilloscope audioScope(256,200,true);
|
||||
|
||||
#define HAND_RADIUS 0.25 // Radius of in-world 'hand' of you
|
||||
|
@ -292,6 +294,7 @@ void initDisplay(void)
|
|||
void init(void)
|
||||
{
|
||||
voxels.init();
|
||||
voxels.setViewerHead(&myHead);
|
||||
myHead.setRenderYaw(start_yaw);
|
||||
|
||||
head_mouse_x = WIDTH/2;
|
||||
|
@ -476,9 +479,9 @@ void display(void)
|
|||
|
||||
GLfloat light_position0[] = { 1.0, 1.0, 0.0, 0.0 };
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
|
||||
GLfloat ambient_color[] = { 0.125, 0.305, 0.5 };
|
||||
GLfloat ambient_color[] = { 0.7, 0.7, 0.8 }; //{ 0.125, 0.305, 0.5 };
|
||||
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_color);
|
||||
GLfloat diffuse_color[] = { 0.5, 0.42, 0.33 };
|
||||
GLfloat diffuse_color[] = { 0.8, 0.7, 0.7 }; //{ 0.5, 0.42, 0.33 };
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_color);
|
||||
GLfloat specular_color[] = { 1.0, 1.0, 1.0, 1.0};
|
||||
glLightfv(GL_LIGHT0, GL_SPECULAR, specular_color);
|
||||
|
@ -627,7 +630,7 @@ void testPointToVoxel()
|
|||
}
|
||||
}
|
||||
|
||||
void addRandomSphere()
|
||||
void addRandomSphere(bool wantColorRandomizer)
|
||||
{
|
||||
float r = randFloatInRange(0.05,0.1);
|
||||
float xc = randFloatInRange(r,(1-r));
|
||||
|
@ -642,7 +645,7 @@ void addRandomSphere()
|
|||
printf("yc=%f\n",yc);
|
||||
printf("zc=%f\n",zc);
|
||||
|
||||
voxels.createSphere(r,xc,yc,zc,s,solid);
|
||||
voxels.createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -761,7 +764,7 @@ void key(unsigned char k, int x, int y)
|
|||
// press the . key to get a new random sphere of voxels added
|
||||
if (k == '.')
|
||||
{
|
||||
addRandomSphere();
|
||||
addRandomSphere(wantColorRandomizer);
|
||||
//testPointToVoxel();
|
||||
}
|
||||
}
|
||||
|
@ -898,8 +901,20 @@ void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) {
|
|||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv)
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
const char* domainIP = getCmdOption(argc, argv, "--domain");
|
||||
if (domainIP) {
|
||||
strcpy(DOMAIN_IP,domainIP);
|
||||
}
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
if (cmdOptionExists(argc, argv, "--local")) {
|
||||
printf("Local Domain MODE!\n");
|
||||
int ip = getLocalAddress();
|
||||
sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
// the callback for our instance of AgentList is attachNewHeadToAgent
|
||||
agentList.linkedDataCreateCallback = &attachNewHeadToAgent;
|
||||
|
||||
|
@ -916,7 +931,7 @@ int main(int argc, char** argv)
|
|||
agentList.startSilentAgentRemovalThread();
|
||||
agentList.startDomainServerCheckInThread();
|
||||
|
||||
glutInit(&argc, argv);
|
||||
glutInit(&argc, (char**)argv);
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
|
||||
glutInitWindowSize(WIDTH, HEIGHT);
|
||||
glutCreateWindow("Interface");
|
||||
|
@ -944,12 +959,16 @@ int main(int argc, char** argv)
|
|||
|
||||
init();
|
||||
|
||||
// Check to see if the user passed in a command line option for randomizing colors
|
||||
if (cmdOptionExists(argc, argv, "--NoColorRandomizer")) {
|
||||
wantColorRandomizer = false;
|
||||
}
|
||||
|
||||
// Check to see if the user passed in a command line option for loading a local
|
||||
// Voxel File. If so, load it now.
|
||||
char* voxelsFilename = getCmdOption(argc, argv, "-i");
|
||||
if (voxelsFilename)
|
||||
{
|
||||
voxels.loadVoxelsFile(voxelsFilename);
|
||||
const char* voxelsFilename = getCmdOption(argc, argv, "-i");
|
||||
if (voxelsFilename) {
|
||||
voxels.loadVoxelsFile(voxelsFilename,wantColorRandomizer);
|
||||
}
|
||||
|
||||
// create thread for receipt of data via UDP
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
#ifndef _WIN32
|
||||
//
|
||||
// main.cpp
|
||||
// mixer
|
||||
//
|
||||
// Created by Stephen Birarda on 2/1/13.
|
||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
|
@ -31,7 +37,7 @@ const unsigned short MIXER_LISTEN_PORT = 55443;
|
|||
const float SAMPLE_RATE = 22050.0;
|
||||
|
||||
const short JITTER_BUFFER_MSECS = 12;
|
||||
const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0f);
|
||||
const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0);
|
||||
|
||||
const int BUFFER_LENGTH_BYTES = 1024;
|
||||
const int BUFFER_LENGTH_SAMPLES_PER_CHANNEL = (BUFFER_LENGTH_BYTES / 2) / sizeof(int16_t);
|
||||
|
@ -44,8 +50,8 @@ const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SA
|
|||
const long MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max();
|
||||
const long MIN_SAMPLE_VALUE = std::numeric_limits<int16_t>::min();
|
||||
|
||||
const float DISTANCE_RATIO = 3.0f/4.2f;
|
||||
const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5f;
|
||||
const float DISTANCE_RATIO = 3.0/4.2;
|
||||
const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5;
|
||||
const int PHASE_DELAY_AT_90 = 20;
|
||||
|
||||
|
||||
|
@ -185,15 +191,13 @@ void *sendBuffer(void *args)
|
|||
// pull the earlier sample for the delayed channel
|
||||
|
||||
int earlierSample = delaySamplePointer[s] *
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex] *
|
||||
otherAgentBuffer->getAttenuationRatio();
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex];
|
||||
|
||||
plateauAdditionOfSamples(delayedChannel[s], earlierSample * weakChannelAmplitudeRatio);
|
||||
}
|
||||
|
||||
int16_t currentSample = (otherAgentBuffer->getNextOutput()[s] *
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex]) *
|
||||
otherAgentBuffer->getAttenuationRatio();
|
||||
distanceCoeffs[lowAgentIndex][highAgentIndex]);
|
||||
plateauAdditionOfSamples(goodChannel[s], currentSample);
|
||||
|
||||
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
|
||||
|
@ -304,12 +308,3 @@ int main(int argc, const char * argv[])
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif _WIN32
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <pthread.h>
|
||||
#include "Agent.h"
|
||||
#include <cstring>
|
||||
#include "UDPSocket.h"
|
||||
|
@ -34,6 +35,8 @@ Agent::Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agent
|
|||
|
||||
activeSocket = NULL;
|
||||
linkedData = NULL;
|
||||
|
||||
pthread_mutex_init(&deleteMutex, NULL);
|
||||
}
|
||||
|
||||
Agent::Agent(const Agent &otherAgent) {
|
||||
|
@ -62,6 +65,8 @@ Agent::Agent(const Agent &otherAgent) {
|
|||
} else {
|
||||
linkedData = NULL;
|
||||
}
|
||||
|
||||
deleteMutex = otherAgent.deleteMutex;
|
||||
}
|
||||
|
||||
Agent& Agent::operator=(Agent otherAgent) {
|
||||
|
@ -69,6 +74,17 @@ Agent& Agent::operator=(Agent otherAgent) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
void Agent::swap(Agent &first, Agent &second) {
|
||||
using std::swap;
|
||||
swap(first.publicSocket, second.publicSocket);
|
||||
swap(first.localSocket, second.localSocket);
|
||||
swap(first.activeSocket, second.activeSocket);
|
||||
swap(first.type, second.type);
|
||||
swap(first.linkedData, second.linkedData);
|
||||
swap(first.agentId, second.agentId);
|
||||
swap(first.deleteMutex, second.deleteMutex);
|
||||
}
|
||||
|
||||
Agent::~Agent() {
|
||||
delete publicSocket;
|
||||
delete localSocket;
|
||||
|
@ -148,16 +164,6 @@ bool Agent::operator==(const Agent& otherAgent) {
|
|||
return matches(otherAgent.publicSocket, otherAgent.localSocket, otherAgent.type);
|
||||
}
|
||||
|
||||
void Agent::swap(Agent &first, Agent &second) {
|
||||
using std::swap;
|
||||
swap(first.publicSocket, second.publicSocket);
|
||||
swap(first.localSocket, second.localSocket);
|
||||
swap(first.activeSocket, second.activeSocket);
|
||||
swap(first.type, second.type);
|
||||
swap(first.linkedData, second.linkedData);
|
||||
swap(first.agentId, second.agentId);
|
||||
}
|
||||
|
||||
bool Agent::matches(sockaddr *otherPublicSocket, sockaddr *otherLocalSocket, char otherAgentType) {
|
||||
// checks if two agent objects are the same agent (same type + local + public address)
|
||||
return type == otherAgentType
|
||||
|
|
|
@ -20,42 +20,45 @@
|
|||
#endif
|
||||
|
||||
class Agent {
|
||||
public:
|
||||
Agent();
|
||||
Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agentType, uint16_t thisAgentId);
|
||||
Agent(const Agent &otherAgent);
|
||||
~Agent();
|
||||
Agent& operator=(Agent otherAgent);
|
||||
bool operator==(const Agent& otherAgent);
|
||||
|
||||
bool matches(sockaddr *otherPublicSocket, sockaddr *otherLocalSocket, char otherAgentType);
|
||||
char getType();
|
||||
void setType(char newType);
|
||||
uint16_t getAgentId();
|
||||
void setAgentId(uint16_t thisAgentId);
|
||||
double getFirstRecvTimeUsecs();
|
||||
void setFirstRecvTimeUsecs(double newTimeUsecs);
|
||||
double getLastRecvTimeUsecs();
|
||||
void setLastRecvTimeUsecs(double newTimeUsecs);
|
||||
sockaddr* getPublicSocket();
|
||||
void setPublicSocket(sockaddr *newSocket);
|
||||
sockaddr* getLocalSocket();
|
||||
void setLocalSocket(sockaddr *newSocket);
|
||||
sockaddr* getActiveSocket();
|
||||
void activatePublicSocket();
|
||||
void activateLocalSocket();
|
||||
AgentData* getLinkedData();
|
||||
void setLinkedData(AgentData *newData);
|
||||
void swap(Agent &first, Agent &second);
|
||||
sockaddr *publicSocket, *localSocket, *activeSocket;
|
||||
char type;
|
||||
uint16_t agentId;
|
||||
double firstRecvTimeUsecs;
|
||||
double lastRecvTimeUsecs;
|
||||
AgentData *linkedData;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Agent* agent);
|
||||
private:
|
||||
void swap(Agent &first, Agent &second);
|
||||
sockaddr *publicSocket, *localSocket, *activeSocket;
|
||||
char type;
|
||||
uint16_t agentId;
|
||||
double firstRecvTimeUsecs;
|
||||
double lastRecvTimeUsecs;
|
||||
AgentData *linkedData;
|
||||
public:
|
||||
Agent();
|
||||
Agent(sockaddr *agentPublicSocket, sockaddr *agentLocalSocket, char agentType, uint16_t thisAgentId);
|
||||
Agent(const Agent &otherAgent);
|
||||
~Agent();
|
||||
Agent& operator=(Agent otherAgent);
|
||||
bool operator==(const Agent& otherAgent);
|
||||
|
||||
bool matches(sockaddr *otherPublicSocket, sockaddr *otherLocalSocket, char otherAgentType);
|
||||
|
||||
pthread_mutex_t deleteMutex;
|
||||
|
||||
char getType();
|
||||
void setType(char newType);
|
||||
uint16_t getAgentId();
|
||||
void setAgentId(uint16_t thisAgentId);
|
||||
double getFirstRecvTimeUsecs();
|
||||
void setFirstRecvTimeUsecs(double newTimeUsecs);
|
||||
double getLastRecvTimeUsecs();
|
||||
void setLastRecvTimeUsecs(double newTimeUsecs);
|
||||
sockaddr* getPublicSocket();
|
||||
void setPublicSocket(sockaddr *newSocket);
|
||||
sockaddr* getLocalSocket();
|
||||
void setLocalSocket(sockaddr *newSocket);
|
||||
sockaddr* getActiveSocket();
|
||||
void activatePublicSocket();
|
||||
void activateLocalSocket();
|
||||
AgentData* getLinkedData();
|
||||
void setLinkedData(AgentData *newData);
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Agent* agent);
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Agent* agent);
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#endif
|
||||
|
||||
const char * SOLO_AGENT_TYPES_STRING = "MV";
|
||||
char DOMAIN_HOSTNAME[] = "highfidelity.below92.com";
|
||||
char DOMAIN_IP[100] = ""; // IP Address will be re-set by lookup on startup
|
||||
char DOMAIN_HOSTNAME[] = "highfidelity.below92.commm";
|
||||
char DOMAIN_IP[100] = "192.168.0.6"; // IP Address will be re-set by lookup on startup
|
||||
const int DOMAINSERVER_PORT = 40102;
|
||||
|
||||
bool silentAgentThreadStopFlag = false;
|
||||
|
@ -67,28 +67,24 @@ unsigned int AgentList::getSocketListenPort() {
|
|||
|
||||
void AgentList::processAgentData(sockaddr *senderAddress, void *packetData, size_t dataBytes) {
|
||||
switch (((char *)packetData)[0]) {
|
||||
case 'D':
|
||||
{
|
||||
case 'D': {
|
||||
// list of agents from domain server
|
||||
updateList((unsigned char *)packetData, dataBytes);
|
||||
break;
|
||||
}
|
||||
case 'H':
|
||||
{
|
||||
case 'H': {
|
||||
// head data from another agent
|
||||
updateAgentWithData(senderAddress, packetData, dataBytes);
|
||||
break;
|
||||
}
|
||||
case 'P':
|
||||
{
|
||||
case 'P': {
|
||||
// ping from another agent
|
||||
//std::cout << "Got ping from " << inet_ntoa(((sockaddr_in *)senderAddress)->sin_addr) << "\n";
|
||||
char reply[] = "R";
|
||||
agentSocket.send(senderAddress, reply, 1);
|
||||
break;
|
||||
}
|
||||
case 'R':
|
||||
{
|
||||
case 'R': {
|
||||
// ping reply from another agent
|
||||
//std::cout << "Got ping reply from " << inet_ntoa(((sockaddr_in *)senderAddress)->sin_addr) << "\n";
|
||||
handlePingReply(senderAddress);
|
||||
|
@ -264,11 +260,22 @@ void *removeSilentAgents(void *args) {
|
|||
checkTimeUSecs = usecTimestampNow();
|
||||
|
||||
for(std::vector<Agent>::iterator agent = agents->begin(); agent != agents->end();) {
|
||||
if ((checkTimeUSecs - agent->getLastRecvTimeUsecs()) > AGENT_SILENCE_THRESHOLD_USECS && agent->getType() != 'V') {
|
||||
|
||||
pthread_mutex_t * agentDeleteMutex = &agent->deleteMutex;
|
||||
|
||||
if ((checkTimeUSecs - agent->getLastRecvTimeUsecs()) > AGENT_SILENCE_THRESHOLD_USECS && agent->getType() != 'V'
|
||||
&& pthread_mutex_trylock(agentDeleteMutex) == 0) {
|
||||
|
||||
std::cout << "Killing agent " << &(*agent) << "\n";
|
||||
|
||||
// make sure the vector isn't currently adding an agent
|
||||
pthread_mutex_lock(&vectorChangeMutex);
|
||||
agent = agents->erase(agent);
|
||||
pthread_mutex_unlock(&vectorChangeMutex);
|
||||
|
||||
// release the delete mutex and destroy it
|
||||
pthread_mutex_unlock(agentDeleteMutex);
|
||||
pthread_mutex_destroy(agentDeleteMutex);
|
||||
} else {
|
||||
agent++;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,6 @@ public:
|
|||
void processAgentData(sockaddr *senderAddress, void *packetData, size_t dataBytes);
|
||||
void updateAgentWithData(sockaddr *senderAddress, void *packetData, size_t dataBytes);
|
||||
void broadcastToAgents(char *broadcastData, size_t dataBytes);
|
||||
void sendToAgent(Agent *destAgent, void *packetData, size_t dataBytes);
|
||||
void pingAgents();
|
||||
char getOwnerType();
|
||||
unsigned int getSocketListenPort();
|
||||
|
|
|
@ -117,9 +117,6 @@ void AudioRingBuffer::parseData(void *data, int size) {
|
|||
dataPtr += sizeof(float);
|
||||
}
|
||||
|
||||
unsigned int attenuationByte = *(dataPtr++);
|
||||
attenuationRatio = attenuationByte / 255.0f;
|
||||
|
||||
memcpy(&bearing, dataPtr, sizeof(float));
|
||||
dataPtr += sizeof(float);
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@ float randFloat () {
|
|||
return (rand() % 10000)/10000.f;
|
||||
}
|
||||
|
||||
int randIntInRange (int min, int max) {
|
||||
return min + (rand() % (max - min));
|
||||
}
|
||||
|
||||
float randFloatInRange (float min,float max) {
|
||||
return min + ((rand() % 10000)/10000.f * (max-min));
|
||||
}
|
||||
|
@ -89,14 +93,11 @@ void switchToResourcesIfRequired() {
|
|||
// then you're using the "-i" flag to set the input file name.
|
||||
// Usage: char * inputFilename = getCmdOption(argc, argv, "-i");
|
||||
// Complaints: Brad :)
|
||||
char* getCmdOption(int argc, char** argv,char* option)
|
||||
{
|
||||
const char* getCmdOption(int argc, const char * argv[],const char* option) {
|
||||
// check each arg
|
||||
for (int i=0; i < argc; i++)
|
||||
{
|
||||
for (int i=0; i < argc; i++) {
|
||||
// if the arg matches the desired option
|
||||
if (strcmp(option,argv[i])==0 && i+1 < argc)
|
||||
{
|
||||
if (strcmp(option,argv[i])==0 && i+1 < argc) {
|
||||
// then return the next option
|
||||
return argv[i+1];
|
||||
}
|
||||
|
@ -110,14 +111,12 @@ char* getCmdOption(int argc, char** argv,char* option)
|
|||
// included while launching the application. Returns bool true/false
|
||||
// Usage: bool wantDump = cmdOptionExists(argc, argv, "-d");
|
||||
// Complaints: Brad :)
|
||||
bool cmdOptionExists(int argc, char** argv,char* option)
|
||||
{
|
||||
|
||||
bool cmdOptionExists(int argc, const char * argv[],const char* option) {
|
||||
// check each arg
|
||||
for (int i=0; i < argc; i++)
|
||||
{
|
||||
for (int i=0; i < argc; i++) {
|
||||
// if the arg matches the desired option
|
||||
if (strcmp(option,argv[i])==0)
|
||||
{
|
||||
if (strcmp(option,argv[i])==0) {
|
||||
// then return the next option
|
||||
return true;
|
||||
}
|
||||
|
@ -172,13 +171,11 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r,
|
|||
|
||||
// Now we actually fill out the voxel code
|
||||
while (octetsDone < voxelSizeInOctets) {
|
||||
|
||||
if (x > xTest) {
|
||||
//<write 1 bit>
|
||||
byte = (byte << 1) | true;
|
||||
xTest += sTest/2.0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//<write 0 bit;>
|
||||
byte = (byte << 1) | false;
|
||||
xTest -= sTest/2.0;
|
||||
|
@ -186,8 +183,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r,
|
|||
bitInByteNDX++;
|
||||
// If we've reached the last bit of the byte, then we want to copy this byte
|
||||
// into our buffer. And get ready to start on a new byte
|
||||
if (bitInByteNDX > 7)
|
||||
{
|
||||
if (bitInByteNDX > 7) {
|
||||
voxelOut[byteNDX]=byte;
|
||||
byteNDX++;
|
||||
bitInByteNDX=0;
|
||||
|
@ -198,8 +194,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r,
|
|||
//<write 1 bit>
|
||||
byte = (byte << 1) | true;
|
||||
yTest += sTest/2.0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//<write 0 bit;>
|
||||
byte = (byte << 1) | false;
|
||||
yTest -= sTest/2.0;
|
||||
|
@ -207,8 +202,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r,
|
|||
bitInByteNDX++;
|
||||
// If we've reached the last bit of the byte, then we want to copy this byte
|
||||
// into our buffer. And get ready to start on a new byte
|
||||
if (bitInByteNDX > 7)
|
||||
{
|
||||
if (bitInByteNDX > 7) {
|
||||
voxelOut[byteNDX]=byte;
|
||||
byteNDX++;
|
||||
bitInByteNDX=0;
|
||||
|
@ -219,8 +213,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r,
|
|||
//<write 1 bit>
|
||||
byte = (byte << 1) | true;
|
||||
zTest += sTest/2.0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//<write 0 bit;>
|
||||
byte = (byte << 1) | false;
|
||||
zTest -= sTest/2.0;
|
||||
|
@ -228,8 +221,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r,
|
|||
bitInByteNDX++;
|
||||
// If we've reached the last bit of the byte, then we want to copy this byte
|
||||
// into our buffer. And get ready to start on a new byte
|
||||
if (bitInByteNDX > 7)
|
||||
{
|
||||
if (bitInByteNDX > 7) {
|
||||
voxelOut[byteNDX]=byte;
|
||||
byteNDX++;
|
||||
bitInByteNDX=0;
|
||||
|
@ -242,11 +234,9 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r,
|
|||
|
||||
// If we've got here, and we didn't fill the last byte, we need to zero pad this
|
||||
// byte before we copy it into our buffer.
|
||||
if (bitInByteNDX > 0 && bitInByteNDX < 7)
|
||||
{
|
||||
if (bitInByteNDX > 0 && bitInByteNDX < 7) {
|
||||
// Pad the last byte
|
||||
while (bitInByteNDX <= 7)
|
||||
{
|
||||
while (bitInByteNDX <= 7) {
|
||||
byte = (byte << 1) | false;
|
||||
bitInByteNDX++;
|
||||
}
|
||||
|
@ -263,8 +253,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r,
|
|||
return voxelOut;
|
||||
}
|
||||
|
||||
void printVoxelCode(unsigned char* voxelCode)
|
||||
{
|
||||
void printVoxelCode(unsigned char* voxelCode) {
|
||||
unsigned char octets = voxelCode[0];
|
||||
unsigned int voxelSizeInBits = octets*3;
|
||||
unsigned int voxelSizeInBytes = (voxelSizeInBits/8)+1;
|
||||
|
@ -277,8 +266,7 @@ void printVoxelCode(unsigned char* voxelCode)
|
|||
printf("voxelSizeInOctets=%d\n",voxelSizeInOctets);
|
||||
printf("voxelBufferSize=%d\n",voxelBufferSize);
|
||||
|
||||
for(int i=0;i<voxelBufferSize;i++)
|
||||
{
|
||||
for(int i=0;i<voxelBufferSize;i++) {
|
||||
printf("i=%d ",i);
|
||||
outputBits(voxelCode[i]);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ double usecTimestamp(timeval *time);
|
|||
double usecTimestampNow();
|
||||
|
||||
float randFloat();
|
||||
int randIntInRange (int min, int max);
|
||||
float randFloatInRange (float min,float max);
|
||||
unsigned char randomColorValue(int minimum);
|
||||
bool randomBoolean();
|
||||
|
@ -33,8 +34,8 @@ bool oneAtBit(unsigned char byte, int bitIndex);
|
|||
|
||||
void switchToResourcesIfRequired();
|
||||
|
||||
char* getCmdOption(int argc, char** argv,char* option);
|
||||
bool cmdOptionExists(int argc, char** argv,char* option);
|
||||
const char* getCmdOption(int argc, const char * argv[],const char* option);
|
||||
bool cmdOptionExists(int argc, const char * argv[],const char* option);
|
||||
unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, unsigned char g, unsigned char b );
|
||||
|
||||
#endif /* defined(__hifi__SharedUtil__) */
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include "OctalCode.h"
|
||||
|
||||
VoxelNode::VoxelNode() {
|
||||
|
||||
childMask = 0;
|
||||
octalCode = NULL;
|
||||
|
||||
// default pointers to child nodes to NULL
|
||||
|
@ -38,17 +36,17 @@ void VoxelNode::addChildAtIndex(int childIndex) {
|
|||
children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
|
||||
}
|
||||
|
||||
// will average the child colors...
|
||||
void VoxelNode::setColorFromAverageOfChildren(int * colorArray) {
|
||||
if (colorArray == NULL) {
|
||||
colorArray = new int[4];
|
||||
memset(colorArray, 0, 4);
|
||||
memset(colorArray, 0, 4*sizeof(int));
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (children[i] != NULL && children[i]->color[3] == 1) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
colorArray[j] += children[i]->color[j];
|
||||
}
|
||||
|
||||
colorArray[3]++;
|
||||
}
|
||||
}
|
||||
|
@ -62,14 +60,54 @@ void VoxelNode::setColorFromAverageOfChildren(int * colorArray) {
|
|||
// set the average color value
|
||||
color[c] = colorArray[c] / colorArray[3];
|
||||
}
|
||||
|
||||
// set the alpha to 1 to indicate that this isn't transparent
|
||||
color[3] = 1;
|
||||
} else {
|
||||
// some children, but not enough
|
||||
// set this node's alpha to 0
|
||||
color[3] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// will detect if children are leaves AND the same color
|
||||
// and in that case will delete the children and make this node
|
||||
// a leaf, returns TRUE if all the leaves are collapsed into a
|
||||
// single node
|
||||
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++) {
|
||||
// if no child, or child doesn't have a color
|
||||
if (children[i] == NULL || children[i]->color[3] != 1) {
|
||||
allChildrenMatch=false;
|
||||
//printf("SADNESS child missing or not colored! i=%d\n",i);
|
||||
break;
|
||||
} else {
|
||||
if (i==0) {
|
||||
red = children[i]->color[0];
|
||||
green = children[i]->color[1];
|
||||
blue = children[i]->color[2];
|
||||
} else if (red != children[i]->color[0] || green != children[i]->color[1] || blue != children[i]->color[2]) {
|
||||
allChildrenMatch=false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (allChildrenMatch) {
|
||||
//printf("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
|
||||
}
|
||||
color[0]=red;
|
||||
color[1]=green;
|
||||
color[2]=blue;
|
||||
color[3]=1; // color is set
|
||||
}
|
||||
return allChildrenMatch;
|
||||
}
|
||||
|
||||
void VoxelNode::setRandomColor(int minimumBrightness) {
|
||||
|
|
|
@ -19,11 +19,11 @@ public:
|
|||
void addChildAtIndex(int childIndex);
|
||||
void setColorFromAverageOfChildren(int * colorArray = NULL);
|
||||
void setRandomColor(int minimumBrightness);
|
||||
bool collapseIdenticalLeaves();
|
||||
|
||||
unsigned char *octalCode;
|
||||
unsigned char color[4];
|
||||
VoxelNode *children[8];
|
||||
unsigned char childMask;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__VoxelNode__) */
|
||||
|
|
|
@ -6,16 +6,45 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifdef _WIN32
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include "SharedUtil.h"
|
||||
#include "OctalCode.h"
|
||||
#include "VoxelTree.h"
|
||||
#include <iostream> // to load voxels from file
|
||||
#include <fstream> // to load voxels from file
|
||||
|
||||
int boundaryDistanceForRenderLevel(unsigned int renderLevel) {
|
||||
switch (renderLevel) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return 100;
|
||||
case 4:
|
||||
return 75;
|
||||
break;
|
||||
case 5:
|
||||
return 50;
|
||||
break;
|
||||
case 6:
|
||||
return 25;
|
||||
break;
|
||||
case 7:
|
||||
return 12;
|
||||
break;
|
||||
default:
|
||||
return 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VoxelTree::VoxelTree() {
|
||||
rootNode = new VoxelNode();
|
||||
rootNode->octalCode = new unsigned char[1];
|
||||
*rootNode->octalCode = (char)0;
|
||||
*rootNode->octalCode = 0;
|
||||
}
|
||||
|
||||
VoxelTree::~VoxelTree() {
|
||||
|
@ -26,22 +55,6 @@ VoxelTree::~VoxelTree() {
|
|||
}
|
||||
}
|
||||
|
||||
int VoxelTree::levelForViewerPosition(float *position) {
|
||||
// get the distance to the viewer
|
||||
// for now the voxel tree starts at 0,0,0
|
||||
float distance = sqrtf(powf(position[0] + 30, 2) + powf(position[2] + 30, 2));
|
||||
|
||||
// go through the if else branch to return the right level
|
||||
// this is a gross way to do this for now for a friday demo
|
||||
if (distance >= 50) {
|
||||
return 3;
|
||||
} else if (distance >= 20) {
|
||||
return 4;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode) {
|
||||
// find the appropriate branch index based on this ancestorNode
|
||||
if (*needleCode > 0) {
|
||||
|
@ -77,45 +90,9 @@ VoxelNode * VoxelTree::createMissingNode(VoxelNode *lastParentNode, unsigned cha
|
|||
}
|
||||
}
|
||||
|
||||
/// If node has color & <= 4 children then prune children
|
||||
void VoxelTree::pruneTree(VoxelNode* pruneAt) {
|
||||
int childCount = 0;
|
||||
|
||||
// determine how many children we have
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (pruneAt->children[i])
|
||||
{
|
||||
childCount++;
|
||||
}
|
||||
}
|
||||
// if appropriate, prune them
|
||||
if (pruneAt->color[3] && childCount <= 4)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (pruneAt->children[i])
|
||||
{
|
||||
delete pruneAt->children[i];
|
||||
pruneAt->children[i]=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, iterate the children and recursively call
|
||||
// prune on all of them
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (pruneAt->children[i])
|
||||
{
|
||||
this->pruneTree(pruneAt->children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int VoxelTree::readNodeData(VoxelNode *destinationNode, unsigned char * nodeData, int bytesLeftToRead) {
|
||||
int VoxelTree::readNodeData(VoxelNode *destinationNode,
|
||||
unsigned char * nodeData,
|
||||
int bytesLeftToRead) {
|
||||
|
||||
// instantiate variable for bytes already read
|
||||
int bytesRead = 1;
|
||||
|
@ -147,7 +124,7 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, unsigned char * nodeData
|
|||
destinationNode->setColorFromAverageOfChildren(colorArray);
|
||||
|
||||
// give this destination node the child mask from the packet
|
||||
destinationNode->childMask = *(nodeData + bytesRead);
|
||||
unsigned char childMask = *(nodeData + bytesRead);
|
||||
|
||||
int childIndex = 0;
|
||||
bytesRead++;
|
||||
|
@ -155,14 +132,16 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, unsigned char * nodeData
|
|||
while (bytesLeftToRead - bytesRead > 0 && childIndex < 8) {
|
||||
// check the exists mask to see if we have a child to traverse into
|
||||
|
||||
if (oneAtBit(destinationNode->childMask, childIndex)) {
|
||||
if (oneAtBit(childMask, childIndex)) {
|
||||
if (destinationNode->children[childIndex] == NULL) {
|
||||
// add a child at that index, if it doesn't exist
|
||||
destinationNode->addChildAtIndex(childIndex);
|
||||
}
|
||||
|
||||
// tell the child to read the subsequent data
|
||||
bytesRead += readNodeData(destinationNode->children[childIndex], nodeData + bytesRead, bytesLeftToRead - bytesRead);
|
||||
bytesRead += readNodeData(destinationNode->children[childIndex],
|
||||
nodeData + bytesRead,
|
||||
bytesLeftToRead - bytesRead);
|
||||
}
|
||||
|
||||
childIndex++;
|
||||
|
@ -185,7 +164,6 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt
|
|||
}
|
||||
|
||||
void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) {
|
||||
int octalCodeBytes = bytesRequiredForCodeLength(*codeColorBuffer);
|
||||
VoxelNode *lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer);
|
||||
|
||||
// create the node if it does not exist
|
||||
|
@ -195,102 +173,170 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) {
|
|||
}
|
||||
|
||||
// give this node its color
|
||||
int octalCodeBytes = bytesRequiredForCodeLength(*codeColorBuffer);
|
||||
memcpy(lastCreatedNode->color, codeColorBuffer + octalCodeBytes, 3);
|
||||
lastCreatedNode->color[3] = 1;
|
||||
}
|
||||
|
||||
unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
||||
unsigned char * stopOctalCode,
|
||||
VoxelNode *currentVoxelNode,
|
||||
int deepestLevel)
|
||||
MarkerNode *currentMarkerNode,
|
||||
float * agentPosition,
|
||||
float thisNodePosition[3],
|
||||
unsigned char * stopOctalCode)
|
||||
{
|
||||
static unsigned char *initialBitstreamPos = bitstreamBuffer;
|
||||
|
||||
int firstIndexToCheck = 0;
|
||||
|
||||
// we'll only be writing data if we're lower than
|
||||
// or at the same level as the stopOctalCode
|
||||
if (*currentVoxelNode->octalCode >= *stopOctalCode) {
|
||||
if ((bitstreamBuffer - initialBitstreamPos) + MAX_TREE_SLICE_BYTES > MAX_VOXEL_PACKET_SIZE) {
|
||||
// we can't send this packet, not enough room
|
||||
// return our octal code as the stop
|
||||
return currentVoxelNode->octalCode;
|
||||
}
|
||||
|
||||
if (strcmp((char *)stopOctalCode, (char *)currentVoxelNode->octalCode) == 0) {
|
||||
// this is is the root node for this packet
|
||||
// add the leading V
|
||||
*(bitstreamBuffer++) = 'V';
|
||||
|
||||
// add its octal code to the packet
|
||||
int octalCodeBytes = bytesRequiredForCodeLength(*currentVoxelNode->octalCode);
|
||||
|
||||
memcpy(bitstreamBuffer, currentVoxelNode->octalCode, octalCodeBytes);
|
||||
bitstreamBuffer += octalCodeBytes;
|
||||
}
|
||||
|
||||
// default color mask is 0, increment pointer for colors
|
||||
*bitstreamBuffer = 0;
|
||||
|
||||
// keep a colorPointer so we can check how many colors were added
|
||||
unsigned char *colorPointer = bitstreamBuffer + 1;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
|
||||
// check if the child exists and is not transparent
|
||||
if (currentVoxelNode->children[i] != NULL
|
||||
&& currentVoxelNode->children[i]->color[3] != 0) {
|
||||
|
||||
// copy in the childs color to bitstreamBuffer
|
||||
memcpy(colorPointer, currentVoxelNode->children[i]->color, 3);
|
||||
colorPointer += 3;
|
||||
|
||||
// set the colorMask by bitshifting the value of childExists
|
||||
*bitstreamBuffer += (1 << (7 - i));
|
||||
}
|
||||
}
|
||||
|
||||
// push the bitstreamBuffer forwards for the number of added colors
|
||||
bitstreamBuffer += (colorPointer - bitstreamBuffer);
|
||||
|
||||
// copy the childMask to the current position of the bitstreamBuffer
|
||||
// and push the buffer pointer forwards
|
||||
*(bitstreamBuffer++) = *currentVoxelNode->octalCode < deepestLevel - 1
|
||||
? currentVoxelNode->childMask
|
||||
: 0;
|
||||
} else {
|
||||
firstIndexToCheck = *stopOctalCode > 0
|
||||
? branchIndexWithDescendant(currentVoxelNode->octalCode, stopOctalCode)
|
||||
: 0;
|
||||
}
|
||||
|
||||
unsigned char * childStopOctalCode = NULL;
|
||||
|
||||
if (currentVoxelNode->childMask == 0) {
|
||||
leavesWrittenToBitstream++;
|
||||
if (stopOctalCode == NULL) {
|
||||
stopOctalCode = rootNode->octalCode;
|
||||
}
|
||||
|
||||
if (*currentVoxelNode->octalCode < deepestLevel - 1) {
|
||||
for (int i = firstIndexToCheck; i < 8; i ++) {
|
||||
// check if we have any children
|
||||
bool hasAtLeastOneChild;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (currentVoxelNode->children[i] != NULL) {
|
||||
hasAtLeastOneChild = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have at least one child, check if it will be worth recursing into our children
|
||||
if (hasAtLeastOneChild) {
|
||||
|
||||
int firstIndexToCheck = 0;
|
||||
unsigned char * childMaskPointer = NULL;
|
||||
|
||||
float halfUnitForVoxel = powf(0.5, *currentVoxelNode->octalCode) * (0.5 * TREE_SCALE);
|
||||
|
||||
float distanceToVoxelCenter = sqrtf(powf(agentPosition[0] - thisNodePosition[0] - halfUnitForVoxel, 2) +
|
||||
powf(agentPosition[1] - thisNodePosition[1] - halfUnitForVoxel, 2) +
|
||||
powf(agentPosition[2] - thisNodePosition[2] - halfUnitForVoxel, 2));
|
||||
|
||||
// if the distance to this voxel's center is less than the threshold
|
||||
// distance for its children, we should send the children
|
||||
if (distanceToVoxelCenter < boundaryDistanceForRenderLevel(*currentVoxelNode->octalCode + 1)) {
|
||||
|
||||
// ask the child to load this bitstream buffer
|
||||
// if they or their descendants fill the MTU we will receive the childStopOctalCode back
|
||||
if (currentVoxelNode->children[i] != NULL) {
|
||||
if (*currentVoxelNode->octalCode < *stopOctalCode
|
||||
&& i > firstIndexToCheck
|
||||
&& childStopOctalCode == NULL) {
|
||||
return currentVoxelNode->children[i]->octalCode;
|
||||
} else {
|
||||
if (oneAtBit(currentVoxelNode->childMask, i)) {
|
||||
childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer, stopOctalCode, currentVoxelNode->children[i], deepestLevel);
|
||||
} else {
|
||||
childStopOctalCode = NULL;
|
||||
// write this voxel's data if we're below or at
|
||||
// or at the same level as the stopOctalCode
|
||||
|
||||
if (*currentVoxelNode->octalCode >= *stopOctalCode) {
|
||||
if ((bitstreamBuffer - initialBitstreamPos) + MAX_TREE_SLICE_BYTES > MAX_VOXEL_PACKET_SIZE) {
|
||||
// we can't send this packet, not enough room
|
||||
// return our octal code as the stop
|
||||
return currentVoxelNode->octalCode;
|
||||
}
|
||||
|
||||
if (strcmp((char *)stopOctalCode, (char *)currentVoxelNode->octalCode) == 0) {
|
||||
// this is is the root node for this packet
|
||||
// add the leading V
|
||||
*(bitstreamBuffer++) = 'V';
|
||||
|
||||
// add its octal code to the packet
|
||||
int octalCodeBytes = bytesRequiredForCodeLength(*currentVoxelNode->octalCode);
|
||||
|
||||
memcpy(bitstreamBuffer, currentVoxelNode->octalCode, octalCodeBytes);
|
||||
bitstreamBuffer += octalCodeBytes;
|
||||
}
|
||||
|
||||
// default color mask is 0, increment pointer for colors
|
||||
*bitstreamBuffer = 0;
|
||||
|
||||
// keep a colorPointer so we can check how many colors were added
|
||||
unsigned char *colorPointer = bitstreamBuffer + 1;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
|
||||
// check if the child exists and is not transparent
|
||||
if (currentVoxelNode->children[i] != NULL
|
||||
&& currentVoxelNode->children[i]->color[3] != 0) {
|
||||
|
||||
// copy in the childs color to bitstreamBuffer
|
||||
memcpy(colorPointer, currentVoxelNode->children[i]->color, 3);
|
||||
colorPointer += 3;
|
||||
|
||||
// set the colorMask by bitshifting the value of childExists
|
||||
*bitstreamBuffer += (1 << (7 - i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// push the bitstreamBuffer forwards for the number of added colors
|
||||
bitstreamBuffer += (colorPointer - bitstreamBuffer);
|
||||
|
||||
// maintain a pointer to this spot in the buffer so we can set our child mask
|
||||
// depending on the results of the recursion below
|
||||
childMaskPointer = bitstreamBuffer++;
|
||||
|
||||
// reset the childMaskPointer for this node to 0
|
||||
*childMaskPointer = 0;
|
||||
} else {
|
||||
firstIndexToCheck = *stopOctalCode > 0
|
||||
? branchIndexWithDescendant(currentVoxelNode->octalCode, stopOctalCode)
|
||||
: 0;
|
||||
}
|
||||
|
||||
if (childStopOctalCode != NULL) {
|
||||
break;
|
||||
unsigned char * arrBufferBeforeChild = bitstreamBuffer;
|
||||
|
||||
for (int i = firstIndexToCheck; i < 8; i ++) {
|
||||
|
||||
// ask the child to load this bitstream buffer
|
||||
// if they or their descendants fill the MTU we will receive the childStopOctalCode back
|
||||
if (currentVoxelNode->children[i] != NULL) {
|
||||
|
||||
if (!oneAtBit(currentMarkerNode->childrenVisitedMask, i)) {
|
||||
|
||||
// create the marker node for this child if it does not yet exist
|
||||
if (currentMarkerNode->children[i] == NULL) {
|
||||
currentMarkerNode->children[i] = new MarkerNode();
|
||||
}
|
||||
|
||||
// calculate the child's position based on the parent position
|
||||
float childNodePosition[3];
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
childNodePosition[j] = thisNodePosition[j];
|
||||
|
||||
if (oneAtBit(branchIndexWithDescendant(currentVoxelNode->octalCode,
|
||||
currentVoxelNode->children[i]->octalCode),
|
||||
(7 - j))) {
|
||||
childNodePosition[j] -= (powf(0.5, *currentVoxelNode->children[i]->octalCode) * TREE_SCALE);
|
||||
}
|
||||
}
|
||||
|
||||
// ask the child to load the bitstream buffer with their data
|
||||
childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer,
|
||||
currentVoxelNode->children[i],
|
||||
currentMarkerNode->children[i],
|
||||
agentPosition,
|
||||
childNodePosition,
|
||||
stopOctalCode);
|
||||
|
||||
if (bitstreamBuffer - arrBufferBeforeChild > 0) {
|
||||
// this child added data to the packet - add it to our child mask
|
||||
if (childMaskPointer != NULL) {
|
||||
*childMaskPointer += (1 << (7 - i));
|
||||
}
|
||||
|
||||
arrBufferBeforeChild = bitstreamBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (childStopOctalCode != NULL) {
|
||||
break;
|
||||
} else {
|
||||
// this child node has been covered
|
||||
// add the appropriate bit to the childrenVisitedMask for the current marker node
|
||||
currentMarkerNode->childrenVisitedMask += 1 << (7 - i);
|
||||
|
||||
// if we are above the stopOctal and we got a NULL code
|
||||
// we cannot go to the next child
|
||||
// so break and return the NULL stop code
|
||||
if (*currentVoxelNode->octalCode < *stopOctalCode) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -319,13 +365,186 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
|
|||
}
|
||||
}
|
||||
|
||||
outputBits(startNode->childMask);
|
||||
unsigned char childMask = 0;
|
||||
|
||||
// ask children to recursively output their trees
|
||||
// if they aren't a leaf
|
||||
for (int k = 0; k < 8; k++) {
|
||||
if (startNode->children[k] != NULL) {
|
||||
printTreeForDebugging(startNode->children[k]);
|
||||
childMask += (1 << (7 - k));
|
||||
}
|
||||
}
|
||||
|
||||
outputBits(childMask);
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
|
||||
bool hasChildren = false;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (startNode->children[i] != NULL) {
|
||||
reaverageVoxelColors(startNode->children[i]);
|
||||
hasChildren = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasChildren) {
|
||||
bool childrenCollapsed = startNode->collapseIdenticalLeaves();
|
||||
|
||||
if (!childrenCollapsed) {
|
||||
startNode->setColorFromAverageOfChildren();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Method: VoxelTree::loadVoxelsFile()
|
||||
// Description: Loads HiFidelity encoded Voxels from a binary file. The current file
|
||||
// format is a stream of single voxels with color data.
|
||||
// Complaints: Brad :)
|
||||
void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
||||
int vCount = 0;
|
||||
|
||||
std::ifstream file(fileName, std::ios::in|std::ios::binary);
|
||||
|
||||
char octets;
|
||||
unsigned int lengthInBytes;
|
||||
|
||||
int totalBytesRead = 0;
|
||||
if(file.is_open()) {
|
||||
printf("loading file...\n");
|
||||
bool bail = false;
|
||||
while (!file.eof() && !bail) {
|
||||
file.get(octets);
|
||||
//printf("octets=%d...\n",octets);
|
||||
totalBytesRead++;
|
||||
lengthInBytes = bytesRequiredForCodeLength(octets)-1; //(octets*3/8)+1;
|
||||
unsigned char * voxelData = new unsigned char[lengthInBytes+1+3];
|
||||
voxelData[0]=octets;
|
||||
char byte;
|
||||
|
||||
for (size_t i = 0; i < lengthInBytes; i++) {
|
||||
file.get(byte);
|
||||
totalBytesRead++;
|
||||
voxelData[i+1] = byte;
|
||||
}
|
||||
// read color data
|
||||
char colorRead;
|
||||
unsigned char red,green,blue;
|
||||
file.get(colorRead);
|
||||
red = (unsigned char)colorRead;
|
||||
file.get(colorRead);
|
||||
green = (unsigned char)colorRead;
|
||||
file.get(colorRead);
|
||||
blue = (unsigned char)colorRead;
|
||||
|
||||
printf("voxel color from file red:%d, green:%d, blue:%d \n",red,green,blue);
|
||||
vCount++;
|
||||
|
||||
int colorRandomizer = wantColorRandomizer ? randIntInRange (-5, 5) : 0;
|
||||
voxelData[lengthInBytes+1] = std::max(0,std::min(255,red + colorRandomizer));
|
||||
voxelData[lengthInBytes+2] = std::max(0,std::min(255,green + colorRandomizer));
|
||||
voxelData[lengthInBytes+3] = std::max(0,std::min(255,blue + colorRandomizer));
|
||||
printf("voxel color after rand red:%d, green:%d, blue:%d\n",
|
||||
voxelData[lengthInBytes+1], voxelData[lengthInBytes+2], voxelData[lengthInBytes+3]);
|
||||
|
||||
//printVoxelCode(voxelData);
|
||||
this->readCodeColorBufferToTree(voxelData);
|
||||
delete voxelData;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Method: VoxelTree::createSphere()
|
||||
// Description: Creates a sphere of voxels in the local system at a given location/radius
|
||||
// To Do: Move this function someplace better?
|
||||
// Complaints: Brad :)
|
||||
void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) {
|
||||
// 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);
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
|
||||
// Psuedocode for creating a sphere:
|
||||
//
|
||||
// for (theta from 0 to 2pi):
|
||||
// for (phi from 0 to pi):
|
||||
// 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;
|
||||
|
||||
if (!solid) {
|
||||
ri=r; // just the outer surface
|
||||
}
|
||||
|
||||
// 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) {
|
||||
//printf("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) {
|
||||
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);
|
||||
|
||||
// gradient color data
|
||||
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) {
|
||||
//printf("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);
|
||||
}
|
||||
|
||||
unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue);
|
||||
this->readCodeColorBufferToTree(voxelData);
|
||||
//printf("voxel data for x:%f y:%f z:%f s:%f\n",x,y,z,s);
|
||||
//printVoxelCode(voxelData);
|
||||
delete voxelData;
|
||||
}
|
||||
}
|
||||
}
|
||||
this->reaverageVoxelColors(this->rootNode);
|
||||
}
|
|
@ -11,9 +11,11 @@
|
|||
|
||||
#include <iostream>
|
||||
#include "VoxelNode.h"
|
||||
#include "MarkerNode.h"
|
||||
|
||||
const int MAX_VOXEL_PACKET_SIZE = 1492;
|
||||
const int MAX_TREE_SLICE_BYTES = 26;
|
||||
const int TREE_SCALE = 10;
|
||||
|
||||
class VoxelTree {
|
||||
VoxelNode * nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode);
|
||||
|
@ -26,16 +28,21 @@ public:
|
|||
VoxelNode *rootNode;
|
||||
int leavesWrittenToBitstream;
|
||||
|
||||
int levelForViewerPosition(float * position);
|
||||
void readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes);
|
||||
void readCodeColorBufferToTree(unsigned char *codeColorBuffer);
|
||||
unsigned char * loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
||||
unsigned char * octalCode,
|
||||
VoxelNode *currentVoxelNode,
|
||||
int deepestLevel);
|
||||
void printTreeForDebugging(VoxelNode *startNode);
|
||||
|
||||
void pruneTree(VoxelNode* pruneAt);
|
||||
void reaverageVoxelColors(VoxelNode *startNode);
|
||||
unsigned char * loadBitstreamBuffer(unsigned char *& bitstreamBuffer,
|
||||
VoxelNode *currentVoxelNode,
|
||||
MarkerNode *currentMarkerNode,
|
||||
float * agentPosition,
|
||||
float thisNodePosition[3],
|
||||
unsigned char * octalCode = NULL);
|
||||
|
||||
void loadVoxelsFile(const char* fileName, bool wantColorRandomizer);
|
||||
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer);
|
||||
};
|
||||
|
||||
int boundaryDistanceForRenderLevel(unsigned int renderLevel);
|
||||
|
||||
#endif /* defined(__hifi__VoxelTree__) */
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <cstdio>
|
||||
|
||||
VoxelAgentData::VoxelAgentData() {
|
||||
lastSentLevel = 0;
|
||||
rootMarkerNode = new MarkerNode();
|
||||
}
|
||||
|
||||
|
@ -20,9 +19,8 @@ VoxelAgentData::~VoxelAgentData() {
|
|||
}
|
||||
|
||||
VoxelAgentData::VoxelAgentData(const VoxelAgentData &otherAgentData) {
|
||||
lastSentLevel = otherAgentData.lastSentLevel;
|
||||
memcpy(position, otherAgentData.position, sizeof(float) * 3);
|
||||
rootMarkerNode = new MarkerNode(*otherAgentData.rootMarkerNode);
|
||||
rootMarkerNode = new MarkerNode();
|
||||
}
|
||||
|
||||
VoxelAgentData* VoxelAgentData::clone() const {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
class VoxelAgentData : public AgentData {
|
||||
public:
|
||||
float position[3];
|
||||
int lastSentLevel;
|
||||
MarkerNode *rootMarkerNode;
|
||||
|
||||
VoxelAgentData();
|
||||
|
|
|
@ -39,48 +39,72 @@ const int MIN_BRIGHTNESS = 64;
|
|||
const float DEATH_STAR_RADIUS = 4.0;
|
||||
const float MAX_CUBE = 0.05f;
|
||||
|
||||
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 10;
|
||||
const int VOXEL_SEND_INTERVAL_USECS = 30 * 1000;
|
||||
const int PACKETS_PER_CLIENT_PER_INTERVAL = 3;
|
||||
|
||||
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
|
||||
|
||||
AgentList agentList('V', VOXEL_LISTEN_PORT);
|
||||
VoxelTree randomTree;
|
||||
|
||||
int randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) {
|
||||
void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) {
|
||||
float r = random ? randFloatInRange(0.05,0.1) : 0.25;
|
||||
float xc = random ? randFloatInRange(r,(1-r)) : 0.5;
|
||||
float yc = random ? randFloatInRange(r,(1-r)) : 0.5;
|
||||
float zc = random ? randFloatInRange(r,(1-r)) : 0.5;
|
||||
float s = (1.0/256); // size of voxels to make up surface of sphere
|
||||
bool solid = true;
|
||||
|
||||
printf("adding sphere:");
|
||||
if (random)
|
||||
printf(" random");
|
||||
printf("\nradius=%f\n",r);
|
||||
printf("xc=%f\n",xc);
|
||||
printf("yc=%f\n",yc);
|
||||
printf("zc=%f\n",zc);
|
||||
|
||||
tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer);
|
||||
}
|
||||
|
||||
void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) {
|
||||
printf("adding scene of spheres...\n");
|
||||
tree->createSphere(0.25,0.5,0.5,0.5,(1.0/256),true,wantColorRandomizer);
|
||||
tree->createSphere(0.030625,0.5,0.5,(0.25-0.06125),(1.0/512),true,true);
|
||||
}
|
||||
|
||||
|
||||
void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) {
|
||||
// randomly generate children for this node
|
||||
// the first level of the tree (where levelsToGo = MAX_VOXEL_TREE_DEPTH_LEVELS) has all 8
|
||||
if (levelsToGo > 0) {
|
||||
|
||||
int grandChildrenFromNode = 0;
|
||||
bool createdChildren = false;
|
||||
int colorArray[4] = {};
|
||||
|
||||
|
||||
createdChildren = false;
|
||||
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (((i == 0 || i == 1 | i == 4 | i == 5) && (randomBoolean() || levelsToGo != 1)) ) {
|
||||
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);
|
||||
|
||||
// fill out the lower levels of the tree using that node as the root node
|
||||
grandChildrenFromNode = randomlyFillVoxelTree(levelsToGo - 1, currentRootNode->children[i]);
|
||||
|
||||
randomlyFillVoxelTree(levelsToGo - 1, currentRootNode->children[i]);
|
||||
|
||||
if (currentRootNode->children[i]->color[3] == 1) {
|
||||
for (int c = 0; c < 3; c++) {
|
||||
colorArray[c] += currentRootNode->children[i]->color[c];
|
||||
}
|
||||
|
||||
|
||||
colorArray[3]++;
|
||||
}
|
||||
|
||||
if (grandChildrenFromNode > 0) {
|
||||
currentRootNode->childMask += (1 << (7 - i));
|
||||
}
|
||||
|
||||
|
||||
createdChildren = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!createdChildren) {
|
||||
// we didn't create any children for this node, making it a leaf
|
||||
// give it a random color
|
||||
|
@ -89,16 +113,88 @@ int randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) {
|
|||
// set the color value for this node
|
||||
currentRootNode->setColorFromAverageOfChildren(colorArray);
|
||||
}
|
||||
|
||||
return createdChildren;
|
||||
} else {
|
||||
// this is a leaf node, just give it a color
|
||||
currentRootNode->setRandomColor(MIN_BRIGHTNESS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void *distributeVoxelsToListeners(void *args) {
|
||||
|
||||
timeval lastSendTime;
|
||||
|
||||
unsigned char *stopOctal;
|
||||
int packetCount;
|
||||
|
||||
int totalBytesSent;
|
||||
|
||||
unsigned char *voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
|
||||
unsigned char *voxelPacketEnd;
|
||||
|
||||
float treeRoot[3] = {0, 0, 0};
|
||||
|
||||
while (true) {
|
||||
gettimeofday(&lastSendTime, NULL);
|
||||
|
||||
// enumerate the agents to send 3 packets to each
|
||||
for (int i = 0; i < agentList.getAgents().size(); i++) {
|
||||
|
||||
Agent *thisAgent = (Agent *)&agentList.getAgents()[i];
|
||||
VoxelAgentData *agentData = (VoxelAgentData *)(thisAgent->getLinkedData());
|
||||
|
||||
// lock this agent's delete mutex so that the delete thread doesn't
|
||||
// kill the agent while we are working with it
|
||||
pthread_mutex_lock(&thisAgent->deleteMutex);
|
||||
|
||||
stopOctal = NULL;
|
||||
packetCount = 0;
|
||||
totalBytesSent = 0;
|
||||
randomTree.leavesWrittenToBitstream = 0;
|
||||
|
||||
for (int j = 0; j < PACKETS_PER_CLIENT_PER_INTERVAL; j++) {
|
||||
voxelPacketEnd = voxelPacket;
|
||||
stopOctal = randomTree.loadBitstreamBuffer(voxelPacketEnd,
|
||||
randomTree.rootNode,
|
||||
agentData->rootMarkerNode,
|
||||
agentData->position,
|
||||
treeRoot,
|
||||
stopOctal);
|
||||
|
||||
agentList.getAgentSocket().send(thisAgent->getActiveSocket(), voxelPacket, voxelPacketEnd - voxelPacket);
|
||||
|
||||
packetCount++;
|
||||
totalBytesSent += voxelPacketEnd - voxelPacket;
|
||||
|
||||
if (agentData->rootMarkerNode->childrenVisitedMask == 255) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// for any agent that has a root marker node with 8 visited children
|
||||
// recursively delete its marker nodes so we can revisit
|
||||
if (agentData->rootMarkerNode->childrenVisitedMask == 255) {
|
||||
delete agentData->rootMarkerNode;
|
||||
agentData->rootMarkerNode = new MarkerNode();
|
||||
}
|
||||
|
||||
// unlock the delete mutex so the other thread can
|
||||
// kill the agent if it has dissapeared
|
||||
pthread_mutex_unlock(&thisAgent->deleteMutex);
|
||||
}
|
||||
|
||||
// dynamically sleep until we need to fire off the next set of voxels
|
||||
double usecToSleep = VOXEL_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSendTime));
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
} else {
|
||||
std::cout << "Last send took too much time, not sleeping!\n";
|
||||
}
|
||||
}
|
||||
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
void attachVoxelAgentDataToAgent(Agent *newAgent) {
|
||||
if (newAgent->getLinkedData() == NULL) {
|
||||
newAgent->setLinkedData(new VoxelAgentData());
|
||||
|
@ -110,26 +206,58 @@ int main(int argc, const char * argv[])
|
|||
{
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
const char* local = "--local";
|
||||
bool wantLocalDomain = cmdOptionExists(argc, argv,local);
|
||||
if (wantLocalDomain) {
|
||||
printf("Local Domain MODE!\n");
|
||||
int ip = getLocalAddress();
|
||||
sprintf(DOMAIN_IP,"%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF));
|
||||
}
|
||||
|
||||
agentList.linkedDataCreateCallback = &attachVoxelAgentDataToAgent;
|
||||
agentList.startSilentAgentRemovalThread();
|
||||
agentList.startDomainServerCheckInThread();
|
||||
|
||||
srand((unsigned)time(0));
|
||||
|
||||
// Check to see if the user passed in a command line option for loading a local
|
||||
// Voxel File. If so, load it now.
|
||||
const char* WANT_COLOR_RANDOMIZER="--WantColorRandomizer";
|
||||
const char* INPUT_FILE="-i";
|
||||
bool wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER);
|
||||
|
||||
// use our method to create a random voxel tree
|
||||
VoxelTree randomTree;
|
||||
printf("wantColorRandomizer=%s\n",(wantColorRandomizer?"yes":"no"));
|
||||
const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE);
|
||||
|
||||
if (voxelsFilename) {
|
||||
randomTree.loadVoxelsFile(voxelsFilename,wantColorRandomizer);
|
||||
}
|
||||
|
||||
const char* ADD_RANDOM_VOXELS="--AddRandomVoxels";
|
||||
if (cmdOptionExists(argc, argv, ADD_RANDOM_VOXELS)) {
|
||||
// create an octal code buffer and load it with 0 so that the recursive tree fill can give
|
||||
// octal codes to the tree nodes that it is creating
|
||||
randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, randomTree.rootNode);
|
||||
}
|
||||
|
||||
// create an octal code buffer and load it with 0 so that the recursive tree fill can give
|
||||
// octal codes to the tree nodes that it is creating
|
||||
randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, randomTree.rootNode);
|
||||
|
||||
unsigned char *voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
|
||||
unsigned char *voxelPacketEnd;
|
||||
|
||||
unsigned char *stopOctal;
|
||||
int packetCount;
|
||||
int totalBytesSent;
|
||||
|
||||
const char* ADD_SPHERE="--AddSphere";
|
||||
const char* ADD_RANDOM_SPHERE="--AddRandomSphere";
|
||||
if (cmdOptionExists(argc, argv, ADD_SPHERE)) {
|
||||
addSphere(&randomTree,false,wantColorRandomizer);
|
||||
} else if (cmdOptionExists(argc, argv, ADD_RANDOM_SPHERE)) {
|
||||
addSphere(&randomTree,true,wantColorRandomizer);
|
||||
}
|
||||
|
||||
const char* NO_ADD_SCENE="--NoAddScene";
|
||||
if (!cmdOptionExists(argc, argv, NO_ADD_SCENE)) {
|
||||
addSphereScene(&randomTree,wantColorRandomizer);
|
||||
}
|
||||
|
||||
pthread_t sendVoxelThread;
|
||||
pthread_create(&sendVoxelThread, NULL, distributeVoxelsToListeners, NULL);
|
||||
|
||||
sockaddr agentPublicAddress;
|
||||
|
||||
char *packetData = new char[MAX_PACKET_SIZE];
|
||||
|
@ -138,17 +266,36 @@ int main(int argc, const char * argv[])
|
|||
// loop to send to agents requesting data
|
||||
while (true) {
|
||||
if (agentList.getAgentSocket().receive(&agentPublicAddress, packetData, &receivedBytes)) {
|
||||
// XXXBHG: Hacked in support for 'I' insert command
|
||||
if (packetData[0] == 'I') {
|
||||
unsigned short int itemNumber = (*((unsigned short int*)&packetData[1]));
|
||||
printf("got I command from client receivedBytes=%ld itemNumber=%d\n",receivedBytes,itemNumber);
|
||||
int atByte = 3;
|
||||
unsigned char* pVoxelData = (unsigned char*)&packetData[3];
|
||||
while (atByte < receivedBytes) {
|
||||
unsigned char octets = (unsigned char)*pVoxelData;
|
||||
int voxelDataSize = bytesRequiredForCodeLength(octets)+3; // 3 for color!
|
||||
randomTree.readCodeColorBufferToTree(pVoxelData);
|
||||
//printf("readCodeColorBufferToTree() of size=%d atByte=%d receivedBytes=%ld\n",voxelDataSize,atByte,receivedBytes);
|
||||
// skip to next
|
||||
pVoxelData+=voxelDataSize;
|
||||
atByte+=voxelDataSize;
|
||||
}
|
||||
}
|
||||
if (packetData[0] == 'H') {
|
||||
|
||||
if (agentList.addOrUpdateAgent(&agentPublicAddress, &agentPublicAddress, packetData[0], agentList.getLastAgentId())) {
|
||||
if (agentList.addOrUpdateAgent(&agentPublicAddress,
|
||||
&agentPublicAddress,
|
||||
packetData[0],
|
||||
agentList.getLastAgentId())) {
|
||||
agentList.increaseAgentId();
|
||||
}
|
||||
|
||||
// parse this agent's position
|
||||
agentList.updateAgentWithData(&agentPublicAddress, (void *)packetData, receivedBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pthread_join(sendVoxelThread, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue