Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jeffrey Ventrella 2013-05-06 11:31:33 -07:00
commit 40213dfedd
16 changed files with 632 additions and 212 deletions

View file

@ -10,4 +10,5 @@ add_subdirectory(interface)
add_subdirectory(injector)
add_subdirectory(pairing-server)
add_subdirectory(space-server)
add_subdirectory(voxel-server)
add_subdirectory(voxel-server)
add_subdirectory(voxel-edit)

View file

@ -260,45 +260,39 @@ void Avatar::reset() {
_head.leanForward = _head.leanSideways = 0;
}
//this pertains to moving the head with the glasses
void Avatar::UpdateGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity)
// this pertains to moving the head with the glasses
// Using serial data, update avatar/render position and angles
{
const float PITCH_ACCEL_COUPLING = 0.5;
const float ROLL_ACCEL_COUPLING = -1.0;
float measured_pitch_rate = serialInterface->getRelativeValue(HEAD_PITCH_RATE);
_head.yawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE);
float measured_lateral_accel = serialInterface->getRelativeValue(ACCEL_X) -
ROLL_ACCEL_COUPLING * serialInterface->getRelativeValue(HEAD_ROLL_RATE);
float measured_fwd_accel = serialInterface->getRelativeValue(ACCEL_Z) -
PITCH_ACCEL_COUPLING * serialInterface->getRelativeValue(HEAD_PITCH_RATE);
float measured_roll_rate = serialInterface->getRelativeValue(HEAD_ROLL_RATE);
//printLog("Pitch Rate: %d ACCEL_Z: %d\n", serialInterface->getRelativeValue(PITCH_RATE),
// serialInterface->getRelativeValue(ACCEL_Z));
//printLog("Pitch Rate: %d ACCEL_X: %d\n", serialInterface->getRelativeValue(PITCH_RATE),
// serialInterface->getRelativeValue(ACCEL_Z));
//printLog("Pitch: %f\n", Pitch);
void Avatar::UpdateGyros(float frametime, SerialInterface* serialInterface, glm::vec3* gravity) {
float measured_pitch_rate = 0.0f;
float measured_roll_rate = 0.0f;
if (serialInterface->active && USING_INVENSENSE_MPU9150) {
measured_pitch_rate = serialInterface->getLastPitch();
_head.yawRate = serialInterface->getLastYaw();
measured_roll_rate = -1 * serialInterface->getLastRoll();
} else {
measured_pitch_rate = serialInterface->getRelativeValue(HEAD_PITCH_RATE);
_head.yawRate = serialInterface->getRelativeValue(HEAD_YAW_RATE);
measured_roll_rate = serialInterface->getRelativeValue(HEAD_ROLL_RATE);
}
// Update avatar head position based on measured gyro rates
const float HEAD_ROTATION_SCALE = 0.70;
const float HEAD_ROLL_SCALE = 0.40;
const float HEAD_LEAN_SCALE = 0.01;
const float MAX_PITCH = 45;
const float MIN_PITCH = -45;
const float MAX_YAW = 85;
const float MIN_YAW = -85;
if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH))
if ((_headPitch < MAX_PITCH) && (_headPitch > MIN_PITCH)) {
addHeadPitch(measured_pitch_rate * -HEAD_ROTATION_SCALE * frametime);
}
addHeadRoll(measured_roll_rate * HEAD_ROLL_SCALE * frametime);
if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW))
addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime);
addLean(-measured_lateral_accel * frametime * HEAD_LEAN_SCALE, -measured_fwd_accel*frametime * HEAD_LEAN_SCALE);
if ((_headYaw < MAX_YAW) && (_headYaw > MIN_YAW)) {
addHeadYaw(_head.yawRate * HEAD_ROTATION_SCALE * frametime);
}
}
float Avatar::getAbsoluteHeadYaw() const {
@ -1566,7 +1560,16 @@ void Avatar::readAvatarDataFromFile() {
FILE* avatarFile = fopen(AVATAR_DATA_FILENAME, "r");
if (avatarFile) {
fscanf(avatarFile, "%f,%f,%f %f", &_position.x, &_position.y, &_position.z, &_bodyYaw);
glm::vec3 readPosition;
float readYaw;
fscanf(avatarFile, "%f,%f,%f %f", &readPosition.x, &readPosition.y, &readPosition.z, &readYaw);
// make sure these values are sane
if (!isnan(readPosition.x) && !isnan(readPosition.y) && !isnan(readPosition.z) && !isnan(readYaw)) {
_position = readPosition;
_bodyYaw = readYaw;
}
fclose(avatarFile);
}
}

View file

@ -6,6 +6,7 @@
//---------------------------------------------------------------------
#include <SharedUtil.h>
#include <VoxelConstants.h>
// #include "Log.h"
#include "Camera.h"
@ -16,7 +17,7 @@ Camera::Camera() {
_tightness = 10.0; // default
_fieldOfView = 60.0; // default
_nearClip = 0.08; // default
_farClip = 50.0; // default
_farClip = 50.0 * TREE_SCALE; // default
_modeShift = 0.0;
_yaw = 0.0;
_pitch = 0.0;

View file

@ -32,6 +32,8 @@ const short NO_READ_MAXIMUM_MSECS = 3000;
const short SAMPLES_TO_DISCARD = 100; // Throw out the first few samples
const int GRAVITY_SAMPLES = 200; // Use the first samples to compute gravity vector
const bool USING_INVENSENSE_MPU9150 = 1;
void SerialInterface::pair() {
#ifdef __APPLE__
@ -62,9 +64,8 @@ void SerialInterface::pair() {
}
// Connect to the serial port
int SerialInterface::initializePort(char* portname, int baud)
{
// connect to the serial port
int SerialInterface::initializePort(char* portname, int baud) {
#ifdef __APPLE__
serialFd = open(portname, O_RDWR | O_NOCTTY | O_NDELAY);
@ -76,8 +77,8 @@ int SerialInterface::initializePort(char* portname, int baud)
}
struct termios options;
tcgetattr(serialFd,&options);
switch(baud)
{
switch(baud) {
case 9600: cfsetispeed(&options,B9600);
cfsetospeed(&options,B9600);
break;
@ -94,16 +95,37 @@ int SerialInterface::initializePort(char* portname, int baud)
cfsetospeed(&options,B9600);
break;
}
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcsetattr(serialFd,TCSANOW,&options);
if (USING_INVENSENSE_MPU9150) {
// block on invensense reads until there is data to read
int currentFlags = fcntl(serialFd, F_GETFL);
fcntl(serialFd, F_SETFL, currentFlags & ~O_NONBLOCK);
// there are extra commands to send to the invensense when it fires up
// this takes it out of SLEEP
write(serialFd, "WR686B01\n", 9);
// delay after the wakeup
usleep(10000);
// this disables streaming so there's no garbage data on reads
write(serialFd, "SD\n", 3);
// flush whatever was produced by the last two commands
tcflush(serialFd, TCIOFLUSH);
}
printLog("Connected.\n");
resetSerial();
resetSerial();
active = true;
#endif
@ -157,62 +179,89 @@ void SerialInterface::renderLevels(int width, int height) {
}
glEnd();
}
}
void convertHexToInt(unsigned char* sourceBuffer, int& destinationInt) {
unsigned int byte[2];
for(int i = 0; i < 2; i++) {
sscanf((char*) sourceBuffer + 2 * i, "%2x", &byte[i]);
}
int16_t result = (byte[0] << 8);
result += byte[1];
destinationInt = result;
}
void SerialInterface::readData() {
#ifdef __APPLE__
// This array sets the rate of trailing averaging for each channel:
// If the sensor rate is 100Hz, 0.001 will make the long term average a 10-second average
const float AVG_RATE[] = {0.002, 0.002, 0.002, 0.002, 0.002, 0.002};
char bufchar[1];
int initialSamples = totalSamples;
while (read(serialFd, &bufchar, 1) > 0) {
serialBuffer[serialBufferPos] = bufchar[0];
serialBufferPos++;
// Have we reached end of a line of input?
if ((bufchar[0] == '\n') || (serialBufferPos >= MAX_BUFFER)) {
std::string serialLine(serialBuffer, serialBufferPos-1);
//printLog("%s\n", serialLine.c_str());
int spot;
//int channel = 0;
std::string val;
for (int i = 0; i < NUM_CHANNELS + 2; i++) {
spot = serialLine.find_first_of(" ", 0);
if (spot != std::string::npos) {
val = serialLine.substr(0,spot);
//printLog("%s\n", val.c_str());
if (i < NUM_CHANNELS) lastMeasured[i] = atoi(val.c_str());
else samplesAveraged = atoi(val.c_str());
} else LED = atoi(serialLine.c_str());
serialLine = serialLine.substr(spot+1, serialLine.length() - spot - 1);
}
// Update Trailing Averages
for (int i = 0; i < NUM_CHANNELS; i++) {
if (totalSamples > SAMPLES_TO_DISCARD) {
trailingAverage[i] = (1.f - AVG_RATE[i])*trailingAverage[i] +
AVG_RATE[i]*(float)lastMeasured[i];
} else {
trailingAverage[i] = (float)lastMeasured[i];
if (USING_INVENSENSE_MPU9150) {
unsigned char gyroBuffer[20];
// ask the invensense for raw gyro data
write(serialFd, "RD684306\n", 9);
read(serialFd, gyroBuffer, 20);
convertHexToInt(gyroBuffer + 6, _lastYaw);
convertHexToInt(gyroBuffer + 10, _lastRoll);
convertHexToInt(gyroBuffer + 14, _lastPitch);
totalSamples++;
} else {
// This array sets the rate of trailing averaging for each channel:
// If the sensor rate is 100Hz, 0.001 will make the long term average a 10-second average
const float AVG_RATE[] = {0.002, 0.002, 0.002, 0.002, 0.002, 0.002};
char bufchar[1];
while (read(serialFd, &bufchar, 1) > 0) {
serialBuffer[serialBufferPos] = bufchar[0];
serialBufferPos++;
// Have we reached end of a line of input?
if ((bufchar[0] == '\n') || (serialBufferPos >= MAX_BUFFER)) {
std::string serialLine(serialBuffer, serialBufferPos-1);
//printLog("%s\n", serialLine.c_str());
int spot;
//int channel = 0;
std::string val;
for (int i = 0; i < NUM_CHANNELS + 2; i++) {
spot = serialLine.find_first_of(" ", 0);
if (spot != std::string::npos) {
val = serialLine.substr(0,spot);
//printLog("%s\n", val.c_str());
if (i < NUM_CHANNELS) lastMeasured[i] = atoi(val.c_str());
else samplesAveraged = atoi(val.c_str());
} else LED = atoi(serialLine.c_str());
serialLine = serialLine.substr(spot+1, serialLine.length() - spot - 1);
}
// Update Trailing Averages
for (int i = 0; i < NUM_CHANNELS; i++) {
if (totalSamples > SAMPLES_TO_DISCARD) {
trailingAverage[i] = (1.f - AVG_RATE[i])*trailingAverage[i] +
AVG_RATE[i]*(float)lastMeasured[i];
} else {
trailingAverage[i] = (float)lastMeasured[i];
}
}
// Use a set of initial samples to compute gravity
if (totalSamples < GRAVITY_SAMPLES) {
gravity.x += lastMeasured[ACCEL_X];
gravity.y += lastMeasured[ACCEL_Y];
gravity.z += lastMeasured[ACCEL_Z];
}
if (totalSamples == GRAVITY_SAMPLES) {
gravity = glm::normalize(gravity);
printLog("gravity: %f,%f,%f\n", gravity.x, gravity.y, gravity.z);
}
totalSamples++;
serialBufferPos = 0;
}
// Use a set of initial samples to compute gravity
if (totalSamples < GRAVITY_SAMPLES) {
gravity.x += lastMeasured[ACCEL_X];
gravity.y += lastMeasured[ACCEL_Y];
gravity.z += lastMeasured[ACCEL_Z];
}
if (totalSamples == GRAVITY_SAMPLES) {
gravity = glm::normalize(gravity);
printLog("gravity: %f,%f,%f\n", gravity.x, gravity.y, gravity.z);
}
totalSamples++;
serialBufferPos = 0;
}
}
@ -234,19 +283,23 @@ void SerialInterface::resetSerial() {
#ifdef __APPLE__
active = false;
totalSamples = 0;
gravity = glm::vec3(0,-1,0);
gettimeofday(&lastGoodRead, NULL);
// Clear the measured and average channel data
for (int i = 0; i < NUM_CHANNELS; i++) {
lastMeasured[i] = 0;
trailingAverage[i] = 0.0;
}
// Clear serial input buffer
for (int i = 1; i < MAX_BUFFER; i++) {
serialBuffer[i] = ' ';
if (!USING_INVENSENSE_MPU9150) {
gravity = glm::vec3(0, -1, 0);
// Clear the measured and average channel data
for (int i = 0; i < NUM_CHANNELS; i++) {
lastMeasured[i] = 0;
trailingAverage[i] = 0.0;
}
// Clear serial input buffer
for (int i = 1; i < MAX_BUFFER; i++) {
serialBuffer[i] = ' ';
}
}
#endif
}

View file

@ -32,16 +32,24 @@
#define HEAD_YAW_RATE 0
#define HEAD_ROLL_RATE 2
extern const bool USING_INVENSENSE_MPU9150;
class SerialInterface {
public:
SerialInterface() { active = false; };
void pair();
void readData();
int getLastYaw() const { return _lastYaw; }
int getLastPitch() const { return _lastPitch; }
int getLastRoll() const { return _lastRoll; }
int getLED() {return LED;};
int getNumSamples() {return samplesAveraged;};
int getValue(int num) {return lastMeasured[num];};
int getRelativeValue(int num) {return static_cast<int>(lastMeasured[num] - trailingAverage[num]);};
float getTrailingValue(int num) {return trailingAverage[num];};
void resetTrailingAverages();
void renderLevels(int width, int height);
bool active;
@ -57,6 +65,9 @@ private:
int totalSamples;
timeval lastGoodRead;
glm::vec3 gravity;
int _lastYaw;
int _lastPitch;
int _lastRoll;
};
#endif

View file

@ -204,8 +204,7 @@ bool justStarted = true;
// Every second, check the frame rates and other stuff
void Timer(int extra)
{
void Timer(int extra) {
gettimeofday(&timerEnd, NULL);
FPS = (float)frameCount / ((float)diffclock(&timerStart, &timerEnd) / 1000.f);
packetsPerSecond = (float)packetCount / ((float)diffclock(&timerStart, &timerEnd) / 1000.f);
@ -223,8 +222,7 @@ void Timer(int extra)
}
}
void displayStats(void)
{
void displayStats(void) {
int statsVerticalOffset = 50;
if (::menuOn == 0) {
statsVerticalOffset = 8;
@ -265,6 +263,7 @@ void displayStats(void)
Agent *avatarMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER);
char avatarMixerStats[200];
if (avatarMixer) {
sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps",
roundf(avatarMixer->getAverageKilobitsPerSecond()),
@ -272,6 +271,7 @@ void displayStats(void)
} else {
sprintf(avatarMixerStats, "No Avatar Mixer");
}
drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats);
if (::perfStatsOn) {
@ -289,8 +289,7 @@ void displayStats(void)
}
}
void initDisplay(void)
{
void initDisplay(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@ -302,8 +301,7 @@ void initDisplay(void)
if (fullscreen) glutFullScreen();
}
void init(void)
{
void init(void) {
voxels.init();
voxels.setViewerAvatar(&myAvatar);
voxels.setCamera(&myCamera);
@ -356,8 +354,7 @@ void terminate () {
exit(EXIT_SUCCESS);
}
void reset_sensors()
{
void reset_sensors() {
myAvatar.setPosition(start_location);
headMouseX = WIDTH/2;
@ -373,16 +370,13 @@ void reset_sensors()
//
// Using gyro data, update both view frustum and avatar head position
//
void updateAvatar(float frametime)
{
void updateAvatar(float frametime) {
float gyroPitchRate = serialPort.getRelativeValue(HEAD_PITCH_RATE);
float gyroYawRate = serialPort.getRelativeValue(HEAD_YAW_RATE );
myAvatar.UpdateGyros(frametime, &serialPort, &gravity);
//
// Update gyro-based mouse (X,Y on screen)
//
const float MIN_MOUSE_RATE = 30.0;
const float MOUSE_SENSITIVITY = 0.1f;
if (powf(gyroYawRate*gyroYawRate +
@ -397,7 +391,7 @@ void updateAvatar(float frametime)
headMouseY = min(headMouseY, HEIGHT);
// Update head and body pitch and yaw based on measured gyro rates
if (::gyroLook) {
if (::gyroLook) {
// Yaw
const float MIN_YAW_RATE = 50;
const float YAW_SENSITIVITY = 1.0;
@ -1686,6 +1680,10 @@ void idle(void) {
handControl.stop();
}
if (serialPort.active && USING_INVENSENSE_MPU9150) {
serialPort.readData();
}
// Sample hardware, update view frustum if needed, Lsend avatar data to mixer/agents
updateAvatar(deltaTime);
@ -1712,7 +1710,7 @@ void idle(void) {
}
// Read serial data
if (serialPort.active) {
if (serialPort.active && !USING_INVENSENSE_MPU9150) {
serialPort.readData();
}
}

View file

@ -8,6 +8,8 @@
// Simple axis aligned box class.
//
#include "SharedUtil.h"
#include "AABox.h"
@ -66,3 +68,50 @@ glm::vec3 AABox::getVertexN(const glm::vec3 &normal) const {
return(res);
}
// determines whether a value is within the extents
static bool isWithin(float value, float corner, float size) {
return value >= corner && value <= corner + size;
}
bool AABox::contains(const glm::vec3& point) const {
return isWithin(point.x, _corner.x, _size.x) &&
isWithin(point.y, _corner.y, _size.y) &&
isWithin(point.z, _corner.z, _size.z);
}
// finds the intersection between a ray and the facing plane on one axis
static bool findIntersection(float origin, float direction, float corner, float size, float& distance) {
if (direction > EPSILON) {
distance = (corner - origin) / direction;
return true;
} else if (direction < -EPSILON) {
distance = (corner + size - origin) / direction;
return true;
}
return false;
}
bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
// handle the trivial case where the box contains the origin
if (contains(origin)) {
distance = 0;
return true;
}
// check each axis
float axisDistance;
if (findIntersection(origin.x, direction.x, _corner.x, _size.x, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z) ||
findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z) ||
findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x)) {
distance = axisDistance;
return true;
}
return false;
}

View file

@ -35,10 +35,13 @@ public:
const glm::vec3& getCorner() const { return _corner; };
const glm::vec3& getSize() const { return _size; };
bool contains(const glm::vec3& point) const;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
private:
glm::vec3 _corner;
glm::vec3 _size;
};
#endif
#endif

View file

@ -225,3 +225,7 @@ int ViewFrustum::boxInFrustum(const AABox& box) const {
return(result);
}
void ViewFrustum::computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const {
origin = _nearTopLeft + x*(_nearTopRight - _nearTopLeft) + y*(_nearBottomLeft - _nearTopLeft);
direction = glm::normalize(origin - _position);
}

View file

@ -98,6 +98,7 @@ public:
int sphereInFrustum(const glm::vec3& center, float radius) const;
int boxInFrustum(const AABox& box) const;
void computePickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const;
};

View file

@ -12,6 +12,8 @@
#ifndef __hifi_VoxelConstants_h__
#define __hifi_VoxelConstants_h__
#include <limits.h>
const int MAX_VOXEL_PACKET_SIZE = 1492;
const int MAX_TREE_SLICE_BYTES = 26;
const int TREE_SCALE = 10;

View file

@ -69,7 +69,7 @@ void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperati
}
}
VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode) {
VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode) const {
// find the appropriate branch index based on this ancestorNode
if (*needleCode > 0) {
int branchForNeedle = branchIndexWithDescendant(ancestorNode->octalCode, needleCode);
@ -157,16 +157,6 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode,
bytesRead += 3;
}
}
// average node's color based on color of children
bool nodeWasDirty = destinationNode->isDirty();
destinationNode->setColorFromAverageOfChildren();
bool nodeIsDirty = destinationNode->isDirty();
if (nodeIsDirty) {
_isDirty = true;
}
if (!nodeWasDirty && nodeIsDirty) {
_nodesChangedFromBitstream++;
}
// give this destination node the child mask from the packet
unsigned char childMask = *(nodeData + bytesRead);
@ -205,7 +195,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode,
return bytesRead;
}
void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes) {
void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes) {
int bytesRead = 0;
unsigned char* bitstreamAt = bitstream;
@ -245,6 +235,13 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt
this->voxelsBytesReadStats.updateAverage(bufferSizeBytes);
}
void VoxelTree::deleteVoxelAt(float x, float y, float z, float s) {
unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0);
deleteVoxelCodeFromTree(octalCode);
delete octalCode; // cleanup memory
}
// Note: uses the codeColorBuffer format, but the color's are ignored, because
// this only finds and deletes the node from the tree.
void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) {
@ -255,20 +252,14 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) {
int lengthInBytes = bytesRequiredForCodeLength(*codeBuffer); // includes octet count, not color!
if (0 == memcmp(nodeToDelete->octalCode,codeBuffer,lengthInBytes)) {
float* vertices = firstVertexForCode(nodeToDelete->octalCode);
delete[] vertices;
if (parentNode) {
float* vertices = firstVertexForCode(parentNode->octalCode);
delete[] vertices;
int childIndex = branchIndexWithDescendant(parentNode->octalCode, codeBuffer);
delete parentNode->children[childIndex]; // delete the child nodes
parentNode->children[childIndex] = NULL; // set it to NULL
reaverageVoxelColors(rootNode); // Fix our colors!! Need to call it on rootNode
_isDirty = true;
}
}
}
@ -279,6 +270,7 @@ void VoxelTree::eraseAllVoxels() {
rootNode = new VoxelNode();
rootNode->octalCode = new unsigned char[1];
*rootNode->octalCode = 0;
_isDirty = true;
}
void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) {
@ -287,6 +279,7 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) {
// create the node if it does not exist
if (*lastCreatedNode->octalCode != *codeColorBuffer) {
lastCreatedNode = createMissingNode(lastCreatedNode, codeColorBuffer);
_isDirty = true;
}
// give this node its color
@ -296,6 +289,9 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) {
memcpy(newColor, codeColorBuffer + octalCodeBytes, 3);
newColor[3] = 1;
lastCreatedNode->setColor(newColor);
if (lastCreatedNode->isDirty()) {
_isDirty = true;
}
}
void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes) {
@ -438,6 +434,16 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
}
}
VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const {
unsigned char* octalCode = pointToVoxel(x,y,z,s,0,0,0);
VoxelNode* node = nodeForOctalCode(rootNode, octalCode, NULL);
if (*node->octalCode != *octalCode) {
node = NULL;
}
delete octalCode; // cleanup memory
return node;
}
void VoxelTree::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue) {
unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue);
this->readCodeColorBufferToTree(voxelData);
@ -546,7 +552,41 @@ int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const
return levelReached;
}
// combines the ray cast arguments into a single object
class RayArgs {
public:
glm::vec3 origin;
glm::vec3 direction;
VoxelNode*& node;
float& distance;
bool found;
};
bool findRayOperation(VoxelNode* node, void* extraData) {
RayArgs* args = static_cast<RayArgs*>(extraData);
AABox box;
node->getAABox(box);
float distance;
if (!box.findRayIntersection(args->origin, args->direction, distance)) {
return false;
}
if (!node->isLeaf()) {
return true; // recurse on children
}
if (!args->found || distance < args->distance) {
args->node = node;
args->distance = distance;
args->found = true;
}
return false;
}
bool VoxelTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelNode*& node, float& distance)
{
RayArgs args = { origin / (float)TREE_SCALE, direction, node, distance };
recurseTreeWithOperation(findRayOperation, &args);
return args.found;
}
int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel,
VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) {
@ -630,15 +670,14 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe
return maxChildLevel;
}
int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum,
unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag) {
int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const {
// How many bytes have we written so far at this level;
int bytesWritten = 0;
// If we're at a node that is out of view, then we can return, because no nodes below us will be in view!
if (!node->isInView(viewFrustum)) {
if (viewFrustum && !node->isInView(*viewFrustum)) {
return bytesWritten;
}
@ -652,8 +691,7 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const Vi
int currentEncodeLevel = 0;
int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel,
node, viewFrustum,
outputBuffer, availableBytes, bag);
node, outputBuffer, availableBytes, bag, viewFrustum);
// if childBytesWritten == 1 then something went wrong... that's not possible
assert(childBytesWritten != 1);
@ -675,9 +713,8 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const Vi
}
int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel,
VoxelNode* node, const ViewFrustum& viewFrustum,
unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag) const {
VoxelNode* node, unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const {
// How many bytes have we written so far at this level;
int bytesAtThisLevel = 0;
@ -689,21 +726,24 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
return bytesAtThisLevel;
}
float distance = node->distanceToCamera(viewFrustum);
float boundaryDistance = boundaryDistanceForRenderLevel(*node->octalCode + 1);
// caller can pass NULL as viewFrustum if they want everything
if (viewFrustum) {
float distance = node->distanceToCamera(*viewFrustum);
float boundaryDistance = boundaryDistanceForRenderLevel(*node->octalCode + 1);
// If we're too far away for our render level, then just return
if (distance >= boundaryDistance) {
return bytesAtThisLevel;
}
// If we're too far away for our render level, then just return
if (distance >= boundaryDistance) {
return bytesAtThisLevel;
}
// If we're at a node that is out of view, then we can return, because no nodes below us will be in view!
// although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if
// we're out of view
if (!node->isInView(viewFrustum)) {
return bytesAtThisLevel;
// If we're at a node that is out of view, then we can return, because no nodes below us will be in view!
// although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if
// we're out of view
if (!node->isInView(*viewFrustum)) {
return bytesAtThisLevel;
}
}
bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more!
// At any given point in writing the bitstream, the largest minimum we might need to flesh out the current level
@ -731,11 +771,11 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
for (int i = 0; i < MAX_CHILDREN; i++) {
VoxelNode* childNode = node->children[i];
bool childExists = (childNode != NULL);
bool childIsInView = (childExists && childNode->isInView(viewFrustum));
bool childIsInView = (childExists && (!viewFrustum || childNode->isInView(*viewFrustum)));
if (childIsInView) {
// Before we determine consider this further, let's see if it's in our LOD scope...
float distance = childNode->distanceToCamera(viewFrustum);
float boundaryDistance = boundaryDistanceForRenderLevel(*childNode->octalCode + 1);
float distance = viewFrustum ? childNode->distanceToCamera(*viewFrustum) : 0;
float boundaryDistance = viewFrustum ? boundaryDistanceForRenderLevel(*childNode->octalCode + 1) : 1;
if (distance < boundaryDistance) {
inViewCount++;
@ -808,7 +848,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
int thisLevel = currentEncodeLevel;
int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode,
viewFrustum, outputBuffer, availableBytes, bag);
outputBuffer, availableBytes, bag, viewFrustum);
// if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space,
// basically, the children below don't contain any info.
@ -848,3 +888,46 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco
} // end keepDiggingDeeper
return bytesAtThisLevel;
}
bool VoxelTree::readFromFileV2(const char* fileName) {
std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate);
if(file.is_open()) {
printLog("loading file...\n");
// get file length....
unsigned long fileLength = file.tellg();
file.seekg( 0, std::ios::beg );
// read the entire file into a buffer, WHAT!? Why not.
unsigned char* entireFile = new unsigned char[fileLength];
file.read((char*)entireFile, fileLength);
readBitstreamToTree(entireFile, fileLength);
delete[] entireFile;
file.close();
return true;
}
return false;
}
void VoxelTree::writeToFileV2(const char* fileName) const {
std::ofstream file(fileName, std::ios::out|std::ios::binary);
if(file.is_open()) {
VoxelNodeBag nodeBag;
nodeBag.insert(rootNode);
static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static
int bytesWritten = 0;
while (!nodeBag.isEmpty()) {
VoxelNode* subTree = nodeBag.extract();
bytesWritten = encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, NULL);
file.write((const char*)&outputBuffer[0], bytesWritten);
}
}
file.close();
}

View file

@ -39,40 +39,48 @@ public:
void eraseAllVoxels();
void processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes);
void readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes);
void readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes);
void readCodeColorBufferToTree(unsigned char *codeColorBuffer);
void deleteVoxelCodeFromTree(unsigned char *codeBuffer);
void printTreeForDebugging(VoxelNode *startNode);
void reaverageVoxelColors(VoxelNode *startNode);
void loadVoxelsFile(const char* fileName, bool wantColorRandomizer);
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer);
void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue);
void deleteVoxelAt(float x, float y, float z, float s);
VoxelNode* getVoxelAt(float x, float y, float z, float s) const;
void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue);
void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color);
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer);
void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL);
int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum,
unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag);
int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const;
int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag);
bool isDirty() const { return _isDirty; };
void clearDirtyBit() { _isDirty = false; };
unsigned long int getNodesChangedFromBitstream() const { return _nodesChangedFromBitstream; };
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelNode*& node, float& distance);
// Note: this assumes the fileFormat is the HIO individual voxels code files
void loadVoxelsFile(const char* fileName, bool wantColorRandomizer);
// these will read/write files that match the wireformat, excluding the 'V' leading
void writeToFileV2(const char* filename) const;
bool readFromFileV2(const char* filename);
private:
int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel,
VoxelNode* node, const ViewFrustum& viewFrustum,
unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag) const;
VoxelNode* node, unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag, const ViewFrustum* viewFrustum) const;
int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel,
VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag);
void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData);
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode);
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const;
VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate);
int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes);

26
voxel-edit/CMakeLists.txt Normal file
View file

@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 2.8)
set(TARGET_NAME voxel-edit)
set(ROOT_DIR ..)
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
# setup for find modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
# set up the external glm library
include(${MACRO_DIR}/IncludeGLM.cmake)
include_glm(${TARGET_NAME} ${ROOT_DIR})
include(${MACRO_DIR}/SetupHifiProject.cmake)
setup_hifi_project(${TARGET_NAME})
# link in the shared library
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
# link in the hifi voxels library
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})

135
voxel-edit/src/main.cpp Normal file
View file

@ -0,0 +1,135 @@
//
// main.cpp
// Voxel Edit
//
// Created by Brad Hefta-Gaub on 05/03/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#include <VoxelTree.h>
#include <SharedUtil.h>
VoxelTree myTree;
int _nodeCount=0;
bool countVoxelsOperation(VoxelNode* node, void* extraData) {
if (node->isColored()){
_nodeCount++;
}
return true; // keep going
}
void addScene(VoxelTree * tree) {
printf("adding scene...\n");
float voxelSize = 1.f/32;
// Here's an example of how to create a voxel.
printf("creating corner points...\n");
tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255);
// Here's an example of how to test if a voxel exists
VoxelNode* node = tree->getVoxelAt(0, 0, 0, voxelSize);
if (node) {
// and how to access it's color
printf("corner point 0,0,0 exists... color is (%d,%d,%d) \n",
node->getColor()[0], node->getColor()[1], node->getColor()[2]);
}
// here's an example of how to delete a voxel
printf("attempting to delete corner point 0,0,0\n");
tree->deleteVoxelAt(0, 0, 0, voxelSize);
// Test to see that the delete worked... it should be FALSE...
if (tree->getVoxelAt(0, 0, 0, voxelSize)) {
printf("corner point 0,0,0 exists...\n");
} else {
printf("corner point 0,0,0 does not exists...\n");
}
// Now some more examples... a little more complex
printf("creating corner points...\n");
tree->createVoxel(0 , 0 , 0 , voxelSize, 255, 255 ,255);
tree->createVoxel(1.0 - voxelSize, 0 , 0 , voxelSize, 255, 0 ,0 );
tree->createVoxel(0 , 1.0 - voxelSize, 0 , voxelSize, 0 , 255 ,0 );
tree->createVoxel(0 , 0 , 1.0 - voxelSize, voxelSize, 0 , 0 ,255);
tree->createVoxel(1.0 - voxelSize, 0 , 1.0 - voxelSize, voxelSize, 255, 0 ,255);
tree->createVoxel(0 , 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 0 , 255 ,255);
tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 0 , voxelSize, 255, 255 ,0 );
tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 255, 255 ,255);
printf("DONE creating corner points...\n");
// Now some more examples... creating some lines using the line primitive
printf("creating voxel lines...\n");
float lineVoxelSize = 0.99f/256;
rgbColor red = {255,0,0};
rgbColor green = {0,255,0};
rgbColor blue = {0,0,255};
tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), lineVoxelSize, blue);
tree->createLine(glm::vec3(0, 0, 0), glm::vec3(1, 0, 0), lineVoxelSize, red);
tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 1, 0), lineVoxelSize, green);
printf("DONE creating lines...\n");
// Now some more examples... creating some spheres using the sphere primitive
int sphereBaseSize = 512;
printf("creating spheres...\n");
tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, false);
printf("one sphere added...\n");
tree->createSphere(0.030625, 0.5, 0.5, (0.25-0.06125), (1.0 / (sphereBaseSize * 2)), true, true);
printf("two spheres added...\n");
tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true);
printf("three spheres added...\n");
tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, (1.0 / (sphereBaseSize * 2)), true, true);
printf("four spheres added...\n");
tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true);
printf("five spheres added...\n");
tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 0.125), (1.0 / (sphereBaseSize * 2)), true, true);
float radius = 0.0125f;
printf("6 spheres added...\n");
tree->createSphere(radius, 0.25, radius * 5.0f, 0.25, (1.0 / 4096), true, true);
printf("7 spheres added...\n");
tree->createSphere(radius, 0.125, radius * 5.0f, 0.25, (1.0 / 4096), true, true);
printf("8 spheres added...\n");
tree->createSphere(radius, 0.075, radius * 5.0f, 0.25, (1.0 / 4096), true, true);
printf("9 spheres added...\n");
tree->createSphere(radius, 0.05, radius * 5.0f, 0.25, (1.0 / 4096), true, true);
printf("10 spheres added...\n");
tree->createSphere(radius, 0.025, radius * 5.0f, 0.25, (1.0 / 4096), true, true);
printf("11 spheres added...\n");
printf("DONE creating spheres...\n");
// Here's an example of how to recurse the tree and do some operation on the nodes as you recurse them.
// This one is really simple, it just couts them...
// Look at the function countVoxelsOperation() for an example of how you could use this function
_nodeCount=0;
tree->recurseTreeWithOperation(countVoxelsOperation);
printf("Nodes after adding scene %d nodes\n", _nodeCount);
printf("DONE adding scene of spheres...\n");
}
int main(int argc, const char * argv[])
{
const char* SAY_HELLO = "--sayHello";
if (cmdOptionExists(argc, argv, SAY_HELLO)) {
printf("I'm just saying hello...\n");
}
const char* DONT_CREATE_FILE = "--dontCreateSceneFile";
bool dontCreateFile = cmdOptionExists(argc, argv, DONT_CREATE_FILE);
if (dontCreateFile) {
printf("You asked us not to create a scene file, so we will not.\n");
} else {
printf("Creating Scene File...\n");
addScene(&myTree);
myTree.writeToFileV2("voxels.hio2");
}
return 0;
}

View file

@ -43,6 +43,7 @@ int PACKETS_PER_CLIENT_PER_INTERVAL = 20;
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
VoxelTree randomTree;
bool wantVoxelPersist = true;
bool wantColorRandomizer = false;
bool debugVoxelSending = false;
@ -83,8 +84,6 @@ void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) {
tree->createVoxel(1.0 - voxelSize, 0 , 0 , voxelSize, 255, 0 ,0 );
tree->createVoxel(0 , 1.0 - voxelSize, 0 , voxelSize, 0 , 255 ,0 );
tree->createVoxel(0 , 0 , 1.0 - voxelSize, voxelSize, 0 , 0 ,255);
tree->createVoxel(1.0 - voxelSize, 0 , 1.0 - voxelSize, voxelSize, 255, 0 ,255);
tree->createVoxel(0 , 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 0 , 255 ,255);
tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 0 , voxelSize, 255, 255 ,0 );
@ -245,9 +244,9 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL) {
if (!agentData->nodeBag.isEmpty()) {
VoxelNode* subTree = agentData->nodeBag.extract();
bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, viewFrustum,
bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree,
&tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
agentData->nodeBag);
agentData->nodeBag, &viewFrustum);
if (agentData->getAvailable() >= bytesWritten) {
agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
@ -299,6 +298,16 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge
}
}
void persistVoxelsWhenDirty() {
// check the dirty bit and persist here...
if (::wantVoxelPersist && ::randomTree.isDirty()) {
printf("saving voxels to file...\n");
randomTree.writeToFileV2("voxels.hio2");
randomTree.clearDirtyBit(); // tree is clean after saving
printf("DONE saving voxels to file...\n");
}
}
void *distributeVoxelsToListeners(void *args) {
AgentList* agentList = AgentList::getInstance();
@ -349,7 +358,6 @@ void attachVoxelAgentDataToAgent(Agent *newAgent) {
}
}
int main(int argc, const char * argv[])
{
AgentList* agentList = AgentList::createInstance(AGENT_TYPE_VOXEL, VOXEL_LISTEN_PORT);
@ -359,9 +367,9 @@ int main(int argc, const char * argv[])
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));
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;
@ -370,56 +378,87 @@ int main(int argc, const char * argv[])
srand((unsigned)time(0));
const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending";
const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending";
::debugVoxelSending = cmdOptionExists(argc, argv, DEBUG_VOXEL_SENDING);
printf("debugVoxelSending=%s\n", (::debugVoxelSending ? "yes" : "no"));
const char* WANT_COLOR_RANDOMIZER = "--wantColorRandomizer";
printf("debugVoxelSending=%s\n", (::debugVoxelSending ? "yes" : "no"));
const char* WANT_COLOR_RANDOMIZER = "--wantColorRandomizer";
::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER);
printf("wantColorRandomizer=%s\n", (::wantColorRandomizer ? "yes" : "no"));
printf("wantColorRandomizer=%s\n", (::wantColorRandomizer ? "yes" : "no"));
// 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* INPUT_FILE = "-i";
const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE);
if (voxelsFilename) {
randomTree.loadVoxelsFile(voxelsFilename,wantColorRandomizer);
}
// By default we will voxel persist, if you want to disable this, then pass in this parameter
const char* NO_VOXEL_PERSIST = "--NoVoxelPersist";
if (cmdOptionExists(argc, argv, NO_VOXEL_PERSIST)) {
::wantVoxelPersist = false;
}
printf("wantVoxelPersist=%s\n", (::wantVoxelPersist ? "yes" : "no"));
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND = "--packetsPerSecond";
const char* packetsPerSecond = getCmdOption(argc, argv, PACKETS_PER_SECOND);
if (packetsPerSecond) {
PACKETS_PER_CLIENT_PER_INTERVAL = atoi(packetsPerSecond)/10;
if (PACKETS_PER_CLIENT_PER_INTERVAL < 1) {
PACKETS_PER_CLIENT_PER_INTERVAL = 1;
}
printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, PACKETS_PER_CLIENT_PER_INTERVAL);
}
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);
}
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);
// if we want Voxel Persistance, load the local file now...
bool persistantFileRead = false;
if (::wantVoxelPersist) {
printf("loading voxels from file...\n");
persistantFileRead = ::randomTree.readFromFileV2("voxels.hio2");
::randomTree.clearDirtyBit(); // the tree is clean since we just loaded it
printf("DONE loading voxels from file...\n");
_nodeCount=0;
::randomTree.recurseTreeWithOperation(countVoxelsOperation);
printf("Nodes after loading scene %d nodes\n", _nodeCount);
}
const char* NO_ADD_SCENE = "--NoAddScene";
if (!cmdOptionExists(argc, argv, NO_ADD_SCENE)) {
addSphereScene(&randomTree,wantColorRandomizer);
// Check to see if the user passed in a command line option for loading an old style local
// Voxel File. If so, load it now. This is not the same as a voxel persist file
const char* INPUT_FILE = "-i";
const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE);
if (voxelsFilename) {
randomTree.loadVoxelsFile(voxelsFilename,wantColorRandomizer);
}
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND = "--packetsPerSecond";
const char* packetsPerSecond = getCmdOption(argc, argv, PACKETS_PER_SECOND);
if (packetsPerSecond) {
PACKETS_PER_CLIENT_PER_INTERVAL = atoi(packetsPerSecond)/10;
if (PACKETS_PER_CLIENT_PER_INTERVAL < 1) {
PACKETS_PER_CLIENT_PER_INTERVAL = 1;
}
printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, PACKETS_PER_CLIENT_PER_INTERVAL);
}
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);
}
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* ADD_SCENE = "--AddScene";
bool addScene = cmdOptionExists(argc, argv, ADD_SCENE);
const char* NO_ADD_SCENE = "--NoAddScene";
bool noAddScene = cmdOptionExists(argc, argv, NO_ADD_SCENE);
if (addScene && noAddScene) {
printf("WARNING! --AddScene and --NoAddScene are mutually exclusive. We will honor --NoAddScene\n");
}
// We will add a scene if...
// 1) we attempted to load a persistant file and it wasn't there
// 2) you asked us to add a scene
// HOWEVER -- we will NEVER add a scene if you explicitly tell us not to!
bool actuallyAddScene = !noAddScene && (addScene || (::wantVoxelPersist && !persistantFileRead));
if (actuallyAddScene) {
addSphereScene(&randomTree,wantColorRandomizer);
}
pthread_t sendVoxelThread;
pthread_create(&sendVoxelThread, NULL, distributeVoxelsToListeners, NULL);
sockaddr agentPublicAddress;
unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE];
@ -427,6 +466,9 @@ int main(int argc, const char * argv[])
// loop to send to agents requesting data
while (true) {
// check to see if we need to persist our voxel state
persistVoxelsWhenDirty();
if (agentList->getAgentSocket().receive(&agentPublicAddress, packetData, &receivedBytes)) {
// XXXBHG: Hacked in support for 'S' SET command
if (packetData[0] == PACKET_HEADER_SET_VOXEL) {