#19197 Create basic visual studio

This commit is contained in:
vincent 2013-03-29 20:20:52 +01:00
commit 622053b38c
22 changed files with 934 additions and 570 deletions

View file

@ -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,

View file

@ -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++) {

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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++;
}

View file

@ -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();

View file

@ -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);

View file

@ -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]);
}

View file

@ -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__) */

View file

@ -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) {

View file

@ -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__) */

View file

@ -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);
}

View file

@ -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__) */

View file

@ -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 {

View file

@ -16,7 +16,6 @@
class VoxelAgentData : public AgentData {
public:
float position[3];
int lastSentLevel;
MarkerNode *rootMarkerNode;
VoxelAgentData();

View file

@ -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;
}