mirror of
https://github.com/lubosz/overte.git
synced 2025-04-19 12:24:01 +02:00
Merge remote-tracking branch 'origin'
This commit is contained in:
commit
191ee71dbb
11 changed files with 435 additions and 28 deletions
|
@ -82,6 +82,30 @@ void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bo
|
|||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsCreated() {
|
||||
return tree->voxelsCreated;
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsCreatedRunningAverage() {
|
||||
return tree->voxelsCreatedStats.getRunningAverage();
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsColored() {
|
||||
return tree->voxelsColored;
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsColoredRunningAverage() {
|
||||
return tree->voxelsColoredStats.getRunningAverage();
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsBytesRead() {
|
||||
return tree->voxelsBytesRead;
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsBytesReadRunningAverage() {
|
||||
return tree->voxelsBytesReadStats.getRunningAverage();
|
||||
}
|
||||
|
||||
|
||||
void VoxelSystem::parseData(void *data, int size) {
|
||||
|
||||
|
@ -97,6 +121,29 @@ void VoxelSystem::parseData(void *data, int size) {
|
|||
// ask the tree to read the "remove" bitstream
|
||||
tree->processRemoveVoxelBitstream((unsigned char*)data,size);
|
||||
break;
|
||||
case 'Z':
|
||||
|
||||
// the Z command is a special command that allows the sender to send high level semantic
|
||||
// requests, like erase all, or add sphere scene, different receivers may handle these
|
||||
// messages differently
|
||||
char* packetData =(char*)data;
|
||||
char* command = &packetData[1]; // start of the command
|
||||
int commandLength = strlen(command); // commands are null terminated strings
|
||||
int totalLength = 1+commandLength+1;
|
||||
|
||||
printf("got Z message len(%d)= %s\n",size,command);
|
||||
|
||||
while (totalLength <= size) {
|
||||
if (0==strcmp(command,(char*)"erase all")) {
|
||||
printf("got Z message == erase all\n");
|
||||
tree->eraseAllVoxels();
|
||||
}
|
||||
if (0==strcmp(command,(char*)"add scene")) {
|
||||
printf("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n");
|
||||
}
|
||||
totalLength += commandLength+1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
setupNewVoxelsForDrawing();
|
||||
|
|
|
@ -37,6 +37,14 @@ public:
|
|||
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);
|
||||
|
||||
long int getVoxelsCreated();
|
||||
long int getVoxelsColored();
|
||||
long int getVoxelsBytesRead();
|
||||
long int getVoxelsCreatedRunningAverage();
|
||||
long int getVoxelsColoredRunningAverage();
|
||||
long int getVoxelsBytesReadRunningAverage();
|
||||
|
||||
private:
|
||||
int voxelsRendered;
|
||||
Head *viewerHead;
|
||||
|
|
|
@ -145,10 +145,11 @@ float renderPitchRate = 0.f;
|
|||
glm::vec3 start_location(6.1f, 0, 1.4f);
|
||||
|
||||
int stats_on = 0; // Whether to show onscreen text overlay with stats
|
||||
bool starsOn = true; // Whether to display the stars
|
||||
bool starsOn = false; // Whether to display the stars
|
||||
bool paintOn = false; // Whether to paint voxels as you fly around
|
||||
VoxelDetail paintingVoxel; // The voxel we're painting if we're painting
|
||||
unsigned char dominantColor = 0; // The dominant color of the voxel we're painting
|
||||
bool perfStatsOn = false; // Do we want to display perfStats?
|
||||
int noise_on = 0; // Whether to add random noise
|
||||
float noise = 1.0; // Overall magnitude scaling for random noise levels
|
||||
|
||||
|
@ -259,7 +260,7 @@ void display_stats(void)
|
|||
char legend[] = "/ - toggle this display, Q - exit, H - show head, M - show hand, T - test audio";
|
||||
drawtext(10, 15, 0.10f, 0, 1.0, 0, legend);
|
||||
|
||||
char legend2[] = "* - toggle stars, & - toggle paint mode";
|
||||
char legend2[] = "* - toggle stars, & - toggle paint mode, '-' - send erase all, '%' - send add scene";
|
||||
drawtext(10, 32, 0.10f, 0, 1.0, 0, legend2);
|
||||
|
||||
glm::vec3 headPos = myHead.getPos();
|
||||
|
@ -286,18 +287,45 @@ void display_stats(void)
|
|||
voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered();
|
||||
drawtext(10,70,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
|
||||
// Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups
|
||||
char** perfStatLinesArray = new char*[PerfStat::getGroupCount()+1];
|
||||
int lines = PerfStat::DumpStats(perfStatLinesArray);
|
||||
int atZ = 150; // arbitrary place on screen that looks good
|
||||
for (int line=0; line < lines; line++) {
|
||||
drawtext(10,atZ,0.10f, 0, 1.0, 0, perfStatLinesArray[line]);
|
||||
delete perfStatLinesArray[line]; // we're responsible for cleanup
|
||||
perfStatLinesArray[line]=NULL;
|
||||
atZ+=20; // height of a line
|
||||
}
|
||||
delete []perfStatLinesArray; // we're responsible for cleanup
|
||||
|
||||
voxelStats.str("");
|
||||
voxelStats << "Voxels Created: " << voxels.getVoxelsCreated() << " (" << voxels.getVoxelsCreatedRunningAverage()
|
||||
<< "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";
|
||||
drawtext(10,250,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
voxelStats << "Voxels Colored: " << voxels.getVoxelsColored() << " (" << voxels.getVoxelsColoredRunningAverage()
|
||||
<< "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";
|
||||
drawtext(10,270,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
voxelStats << "Voxels Bytes Read: " << voxels.getVoxelsBytesRead()
|
||||
<< " (" << voxels.getVoxelsBytesReadRunningAverage() << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";
|
||||
drawtext(10,290,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
long int voxelsBytesPerColored = voxels.getVoxelsColored() ? voxels.getVoxelsBytesRead()/voxels.getVoxelsColored() : 0;
|
||||
long int voxelsBytesPerColoredAvg = voxels.getVoxelsColoredRunningAverage() ?
|
||||
voxels.getVoxelsBytesReadRunningAverage()/voxels.getVoxelsColoredRunningAverage() : 0;
|
||||
|
||||
voxelStats << "Voxels Bytes per Colored: " << voxelsBytesPerColored
|
||||
<< " (" << voxelsBytesPerColoredAvg << "/sec in last "<< COUNTETSTATS_TIME_FRAME << " seconds) ";
|
||||
drawtext(10,310,0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
|
||||
|
||||
if (::perfStatsOn) {
|
||||
// Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups
|
||||
char** perfStatLinesArray = new char*[PerfStat::getGroupCount()+1];
|
||||
int lines = PerfStat::DumpStats(perfStatLinesArray);
|
||||
int atZ = 150; // arbitrary place on screen that looks good
|
||||
for (int line=0; line < lines; line++) {
|
||||
drawtext(10,atZ,0.10f, 0, 1.0, 0, perfStatLinesArray[line]);
|
||||
delete perfStatLinesArray[line]; // we're responsible for cleanup
|
||||
perfStatLinesArray[line]=NULL;
|
||||
atZ+=20; // height of a line
|
||||
}
|
||||
delete []perfStatLinesArray; // we're responsible for cleanup
|
||||
}
|
||||
|
||||
/*
|
||||
std::stringstream angles;
|
||||
angles << "render_yaw: " << myHead.getRenderYaw() << ", Yaw: " << myHead.getYaw();
|
||||
|
@ -513,9 +541,10 @@ void simulateHead(float frametime)
|
|||
|
||||
glm::vec3 headPos = myHead.getPos();
|
||||
|
||||
::paintingVoxel.x = headPos.z/-10.0; // voxel space x is negative z head space
|
||||
::paintingVoxel.y = headPos.y/-10.0; // voxel space y is negative y head space
|
||||
::paintingVoxel.z = headPos.x/-10.0; // voxel space z is negative x head space
|
||||
// For some reason, we don't want to flip X and Z here.
|
||||
::paintingVoxel.x = headPos.x/-10.0;
|
||||
::paintingVoxel.y = headPos.y/-10.0;
|
||||
::paintingVoxel.z = headPos.z/-10.0;
|
||||
|
||||
unsigned char* bufferOut;
|
||||
int sizeOut;
|
||||
|
@ -774,6 +803,20 @@ void testPointToVoxel()
|
|||
}
|
||||
}
|
||||
|
||||
void sendVoxelServerEraseAll() {
|
||||
char message[100];
|
||||
sprintf(message,"%c%s",'Z',"erase all");
|
||||
int messageSize = strlen(message)+1;
|
||||
::agentList.broadcastToAgents(message, messageSize,AgentList::AGENTS_OF_TYPE_VOXEL);
|
||||
}
|
||||
|
||||
void sendVoxelServerAddScene() {
|
||||
char message[100];
|
||||
sprintf(message,"%c%s",'Z',"add scene");
|
||||
int messageSize = strlen(message)+1;
|
||||
::agentList.broadcastToAgents(message, messageSize,AgentList::AGENTS_OF_TYPE_VOXEL);
|
||||
}
|
||||
|
||||
void shiftPaintingColor()
|
||||
{
|
||||
// About the color of the paintbrush... first determine the dominant color
|
||||
|
@ -883,11 +926,11 @@ void key(unsigned char k, int x, int y)
|
|||
if (k == '*') ::starsOn = !::starsOn; // toggle stars
|
||||
if (k == '&') {
|
||||
::paintOn = !::paintOn; // toggle paint
|
||||
setupPaintingVoxel(); // also randomizes colors
|
||||
}
|
||||
if (k == '^') {
|
||||
shiftPaintingColor(); // shifts randomize color between R,G,B dominant
|
||||
::setupPaintingVoxel(); // also randomizes colors
|
||||
}
|
||||
if (k == '^') ::shiftPaintingColor(); // shifts randomize color between R,G,B dominant
|
||||
if (k == '-') ::sendVoxelServerEraseAll(); // sends erase all command to voxel server
|
||||
if (k == '%') ::sendVoxelServerAddScene(); // sends add scene command to voxel server
|
||||
if (k == 'n')
|
||||
{
|
||||
noise_on = !noise_on; // Toggle noise
|
||||
|
@ -963,7 +1006,7 @@ void *networkReceive(void *args)
|
|||
if (incomingPacket[0] == 't') {
|
||||
// Pass everything but transmitter data to the agent list
|
||||
myHead.hand->processTransmitterData(incomingPacket, bytesReceived);
|
||||
} else if (incomingPacket[0] == 'V' || incomingPacket[0] == 'R') {
|
||||
} else if (incomingPacket[0] == 'V' || incomingPacket[0] == 'Z') {
|
||||
voxels.parseData(incomingPacket, bytesReceived);
|
||||
} else {
|
||||
agentList.processAgentData(&senderAddress, incomingPacket, bytesReceived);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include "AgentList.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -78,14 +79,14 @@ void AgentList::processAgentData(sockaddr *senderAddress, void *packetData, size
|
|||
updateAgentWithData(senderAddress, packetData, dataBytes);
|
||||
break;
|
||||
}
|
||||
case 'P': {
|
||||
case PACKET_HEADER_PING: {
|
||||
// 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 PACKET_HEADER_PING_REPLY: {
|
||||
// ping reply from another agent
|
||||
//std::cout << "Got ping reply from " << inet_ntoa(((sockaddr_in *)senderAddress)->sin_addr) << "\n";
|
||||
handlePingReply(senderAddress);
|
||||
|
@ -225,7 +226,8 @@ void AgentList::broadcastToAgents(char *broadcastData, size_t dataBytes,const ch
|
|||
}
|
||||
|
||||
void AgentList::pingAgents() {
|
||||
char payload[] = "P";
|
||||
char payload[1];
|
||||
*payload = PACKET_HEADER_PING;
|
||||
|
||||
for(std::vector<Agent>::iterator agent = agents.begin(); agent != agents.end(); agent++) {
|
||||
if (agent->getType() == 'I') {
|
||||
|
|
90
shared/src/CounterStats.cpp
Normal file
90
shared/src/CounterStats.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// CounterStats.cpp
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2013/04/08.
|
||||
//
|
||||
// Poor-man's counter stats collector class. Useful for collecting running averages
|
||||
// and other stats for countable things.
|
||||
//
|
||||
//
|
||||
|
||||
#include "CounterStats.h"
|
||||
#include <cstdio>
|
||||
#include <sys/time.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
|
||||
//private:
|
||||
// long int currentCount;
|
||||
// long int currentDelta;
|
||||
// double currentTime;
|
||||
// double totalTime;
|
||||
//
|
||||
// long int countSamples[COUNTETSTATS_SAMPLES_TO_KEEP] = {};
|
||||
// long int deltaSamples[COUNTETSTATS_SAMPLES_TO_KEEP] = {};
|
||||
// double timeSamples[COUNTETSTATS_SAMPLES_TO_KEEP] = {};
|
||||
// int sampleAt;
|
||||
|
||||
|
||||
void CounterStatHistory::recordSample(long int thisCount) {
|
||||
timeval now;
|
||||
gettimeofday(&now,NULL);
|
||||
double nowSeconds = (now.tv_usec/1000000.0)+(now.tv_sec);
|
||||
this->recordSample(nowSeconds,thisCount);
|
||||
}
|
||||
|
||||
void CounterStatHistory::recordSample(double thisTime, long int thisCount) {
|
||||
|
||||
// how much did we change since last sample?
|
||||
long int thisDelta = thisCount - this->lastCount;
|
||||
double elapsed = thisTime - this->lastTime;
|
||||
|
||||
// record the latest values
|
||||
this->currentCount = thisCount;
|
||||
this->currentTime = thisTime;
|
||||
this->currentDelta = thisDelta;
|
||||
|
||||
//printf("CounterStatHistory[%s]::recordSample(thisTime %lf, thisCount= %ld)\n",this->name.c_str(),thisTime,thisCount);
|
||||
|
||||
// if more than 1/10th of a second has passed, then record
|
||||
// things in our rolling history
|
||||
if (elapsed > 0.1) {
|
||||
this->lastTime = thisTime;
|
||||
this->lastCount = thisCount;
|
||||
|
||||
// record it in our history...
|
||||
this->sampleAt = (this->sampleAt+1)%COUNTETSTATS_SAMPLES_TO_KEEP;
|
||||
if (this->sampleCount<COUNTETSTATS_SAMPLES_TO_KEEP) {
|
||||
this->sampleCount++;
|
||||
}
|
||||
this->countSamples[this->sampleAt]=thisCount;
|
||||
this->timeSamples[this->sampleAt]=thisTime;
|
||||
this->deltaSamples[this->sampleAt]=thisDelta;
|
||||
|
||||
//printf("CounterStatHistory[%s]::recordSample() ACTUALLY RECORDING IT sampleAt=%d thisTime %lf, thisCount= %ld)\n",this->name.c_str(),this->sampleAt,thisTime,thisCount);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
long int CounterStatHistory::getRunningAverage() {
|
||||
// before we calculate our running average, always "reset" the current count, with the current time
|
||||
// this will flush out old data, if we haven't been adding any new data.
|
||||
this->recordSample(this->currentCount);
|
||||
|
||||
long int runningTotal = 0;
|
||||
double minTime = this->timeSamples[0];
|
||||
double maxTime = this->timeSamples[0];
|
||||
|
||||
for (int i =0; i < this->sampleCount; i++) {
|
||||
minTime = std::min(minTime,this->timeSamples[i]);
|
||||
maxTime = std::max(maxTime,this->timeSamples[i]);
|
||||
runningTotal += this->deltaSamples[i];
|
||||
}
|
||||
|
||||
double elapsedTime = maxTime-minTime;
|
||||
long int runningAverage = runningTotal/elapsedTime;
|
||||
return runningAverage;
|
||||
}
|
79
shared/src/CounterStats.h
Normal file
79
shared/src/CounterStats.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// CounterStats.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 3/29/13.
|
||||
//
|
||||
// Poor-man's counter stats collector class. Useful for collecting running averages
|
||||
// and other stats for countable things.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef __hifi__CounterStats__
|
||||
#define __hifi__CounterStats__
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
// TIME_FRAME should be SAMPLES_TO_KEEP * TIME_BETWEEN_SAMPLES
|
||||
#define COUNTETSTATS_SAMPLES_TO_KEEP 50
|
||||
#define COUNTETSTATS_TIME_BETWEEN_SAMPLES 0.1
|
||||
#define COUNTETSTATS_TIME_FRAME (COUNTETSTATS_SAMPLES_TO_KEEP*COUNTETSTATS_TIME_BETWEEN_SAMPLES)
|
||||
|
||||
class CounterStatHistory {
|
||||
|
||||
private:
|
||||
long int currentCount;
|
||||
long int currentDelta;
|
||||
double currentTime;
|
||||
|
||||
long int lastCount;
|
||||
double lastTime;
|
||||
|
||||
double totalTime;
|
||||
|
||||
long int countSamples[COUNTETSTATS_SAMPLES_TO_KEEP];
|
||||
long int deltaSamples[COUNTETSTATS_SAMPLES_TO_KEEP];
|
||||
double timeSamples[COUNTETSTATS_SAMPLES_TO_KEEP];
|
||||
int sampleAt;
|
||||
int sampleCount;
|
||||
|
||||
public:
|
||||
std::string name;
|
||||
|
||||
CounterStatHistory(std::string myName):
|
||||
currentCount(0), currentDelta(0),currentTime(0.0),
|
||||
lastCount(0),lastTime(0.0),
|
||||
totalTime(0.0),
|
||||
sampleAt(-1),sampleCount(0), name(myName) {};
|
||||
|
||||
CounterStatHistory():
|
||||
currentCount(0), currentDelta(0),currentTime(0.0),
|
||||
lastCount(0),lastTime(0.0),
|
||||
totalTime(0.0),
|
||||
sampleAt(-1),sampleCount(0) {};
|
||||
|
||||
CounterStatHistory(std::string myName, double initialTime, long int initialCount) :
|
||||
currentCount(initialCount), currentDelta(0), currentTime(initialTime),
|
||||
lastCount(initialCount),lastTime(initialTime),
|
||||
totalTime(initialTime),
|
||||
sampleAt(-1), sampleCount(0), name(myName) {};
|
||||
|
||||
void recordSample(long int thisCount);
|
||||
void recordSample(double thisTime, long int thisCount);
|
||||
long int getRunningAverage();
|
||||
|
||||
long int getAverage() {
|
||||
return currentCount/totalTime;
|
||||
};
|
||||
|
||||
double getTotalTime() {
|
||||
return totalTime;
|
||||
};
|
||||
long int getCount() {
|
||||
return currentCount;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__CounterStat__) */
|
16
shared/src/PacketHeaders.h
Normal file
16
shared/src/PacketHeaders.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// PacketHeaders.h
|
||||
// hifi
|
||||
//
|
||||
// Created by Stephen Birarda on 4/8/13.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef hifi_PacketHeaders_h
|
||||
#define hifi_PacketHeaders_h
|
||||
|
||||
const char PACKET_HEADER_DOMAIN = 'D';
|
||||
const char PACKET_HEADER_PING = 'P';
|
||||
const char PACKET_HEADER_PING_REPLY = 'R';
|
||||
|
||||
#endif
|
|
@ -10,6 +10,7 @@
|
|||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include "SharedUtil.h"
|
||||
#include "CounterStats.h"
|
||||
#include "OctalCode.h"
|
||||
#include "VoxelTree.h"
|
||||
#include <iostream> // to load voxels from file
|
||||
|
@ -44,6 +45,15 @@ VoxelTree::VoxelTree() {
|
|||
rootNode = new VoxelNode();
|
||||
rootNode->octalCode = new unsigned char[1];
|
||||
*rootNode->octalCode = 0;
|
||||
|
||||
// Some stats tracking
|
||||
this->voxelsCreated = 0; // when a voxel is created in the tree (object new'd)
|
||||
this->voxelsColored = 0; // when a voxel is colored/set in the tree (object may have already existed)
|
||||
this->voxelsBytesRead = 0;
|
||||
voxelsCreatedStats.name = "voxelsCreated";
|
||||
voxelsColoredStats.name = "voxelsColored";
|
||||
voxelsBytesReadStats.name = "voxelsBytesRead";
|
||||
|
||||
}
|
||||
|
||||
VoxelTree::~VoxelTree() {
|
||||
|
@ -94,6 +104,9 @@ VoxelNode * VoxelTree::createMissingNode(VoxelNode *lastParentNode, unsigned cha
|
|||
}
|
||||
}
|
||||
|
||||
// BHG Notes: We appear to call this function for every Voxel Node getting created.
|
||||
// This is recursive in nature. So, for example, if we are given an octal code for
|
||||
// a 1/256th size voxel, we appear to call this function 8 times. Maybe??
|
||||
int VoxelTree::readNodeData(VoxelNode *destinationNode,
|
||||
unsigned char * nodeData,
|
||||
int bytesLeftToRead) {
|
||||
|
@ -107,11 +120,15 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode,
|
|||
// create the child if it doesn't exist
|
||||
if (destinationNode->children[i] == NULL) {
|
||||
destinationNode->addChildAtIndex(i);
|
||||
this->voxelsCreated++;
|
||||
this->voxelsCreatedStats.recordSample(this->voxelsCreated);
|
||||
}
|
||||
|
||||
// pull the color for this child
|
||||
memcpy(destinationNode->children[i]->color, nodeData + bytesRead, 3);
|
||||
destinationNode->children[i]->color[3] = 1;
|
||||
this->voxelsColored++;
|
||||
this->voxelsColoredStats.recordSample(this->voxelsColored);
|
||||
|
||||
bytesRead += 3;
|
||||
}
|
||||
|
@ -133,6 +150,8 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode,
|
|||
if (destinationNode->children[childIndex] == NULL) {
|
||||
// add a child at that index, if it doesn't exist
|
||||
destinationNode->addChildAtIndex(childIndex);
|
||||
this->voxelsCreated++;
|
||||
this->voxelsCreatedStats.recordSample(this->voxelsCreated);
|
||||
}
|
||||
|
||||
// tell the child to read the subsequent data
|
||||
|
@ -158,6 +177,9 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt
|
|||
|
||||
int octalCodeBytes = bytesRequiredForCodeLength(*bitstream);
|
||||
readNodeData(bitstreamRootNode, bitstream + octalCodeBytes, bufferSizeBytes - octalCodeBytes);
|
||||
|
||||
this->voxelsBytesRead += bufferSizeBytes;
|
||||
this->voxelsBytesReadStats.recordSample(this->voxelsBytesRead);
|
||||
}
|
||||
|
||||
// Note: uses the codeColorBuffer format, but the color's are ignored, because
|
||||
|
@ -202,6 +224,16 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char *codeBuffer) {
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelTree::eraseAllVoxels() {
|
||||
|
||||
// XXXBHG Hack attack - is there a better way to erase the voxel tree?
|
||||
|
||||
delete rootNode; // this will recurse and delete all children
|
||||
rootNode = new VoxelNode();
|
||||
rootNode->octalCode = new unsigned char[1];
|
||||
*rootNode->octalCode = 0;
|
||||
}
|
||||
|
||||
void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) {
|
||||
VoxelNode *lastCreatedNode = nodeForOctalCode(rootNode, codeColorBuffer, NULL);
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#ifndef __hifi__VoxelTree__
|
||||
#define __hifi__VoxelTree__
|
||||
|
||||
#include "CounterStats.h"
|
||||
|
||||
#include "VoxelNode.h"
|
||||
#include "MarkerNode.h"
|
||||
|
||||
|
@ -20,13 +22,25 @@ class VoxelTree {
|
|||
VoxelNode * nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode);
|
||||
VoxelNode * createMissingNode(VoxelNode *lastParentNode, unsigned char *deepestCodeToCreate);
|
||||
int readNodeData(VoxelNode *destinationNode, unsigned char * nodeData, int bufferSizeBytes);
|
||||
|
||||
|
||||
public:
|
||||
long int voxelsCreated;
|
||||
long int voxelsColored;
|
||||
long int voxelsBytesRead;
|
||||
|
||||
CounterStatHistory voxelsCreatedStats;
|
||||
CounterStatHistory voxelsColoredStats;
|
||||
CounterStatHistory voxelsBytesReadStats;
|
||||
|
||||
VoxelTree();
|
||||
~VoxelTree();
|
||||
|
||||
VoxelNode *rootNode;
|
||||
int leavesWrittenToBitstream;
|
||||
|
||||
void eraseAllVoxels();
|
||||
|
||||
void processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes);
|
||||
void readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes);
|
||||
void readCodeColorBufferToTree(unsigned char *codeColorBuffer);
|
||||
|
|
|
@ -38,13 +38,31 @@ function send_voxels($inputFileName,$server,$port,$command) {
|
|||
socket_close($socketHandle);
|
||||
}
|
||||
|
||||
function send_zcommand($server,$port,$command) {
|
||||
$socketHandle = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
||||
$serverIP = $server;
|
||||
$serverSendPort = $port;
|
||||
|
||||
// [1:'Z'][2:command][0]...
|
||||
$netData = pack("c",ord('Z'));
|
||||
$netData .= $command;
|
||||
$netData .= pack("c",0);
|
||||
|
||||
$packetSize = 2+strlen($command);
|
||||
echo "sending packet server=$serverIP port=$serverSendPort size=$packetSize \n";
|
||||
$result = socket_sendto($socketHandle, $netData, $packetSize, 0, $serverIP, $serverSendPort);
|
||||
socket_close($socketHandle);
|
||||
}
|
||||
|
||||
function testmode_send_voxels($server,$port) {
|
||||
echo "psych! test mode not implemented!\n";
|
||||
}
|
||||
|
||||
$options = getopt("i:s:p:c:",array('testmode'));
|
||||
$options = getopt("i:s:p:c:",array('testmode','zcommand:'));
|
||||
//print_r($options);
|
||||
//break;
|
||||
|
||||
if (empty($options['i']) || empty($options['i'])) {
|
||||
if (empty($options['i']) && empty($options['zcommand'])) {
|
||||
echo "USAGE: sendvoxels.php -i 'inputFileName' -s [serverip] -p [port] -c [I|R] \n";
|
||||
} else {
|
||||
$filename = $options['i'];
|
||||
|
@ -54,6 +72,7 @@ if (empty($options['i']) || empty($options['i'])) {
|
|||
switch($command) {
|
||||
case 'I':
|
||||
case 'R':
|
||||
case 'Z':
|
||||
//$command is good
|
||||
break;
|
||||
default:
|
||||
|
@ -63,6 +82,9 @@ if (empty($options['i']) || empty($options['i'])) {
|
|||
if ($options['testmode']) {
|
||||
echo "TEST MODE Sending Voxels server:$server port:$port \n";
|
||||
testmode_send_voxels($server,$port);
|
||||
} else if ($options['zcommand'] && $command=='Z') {
|
||||
echo "Sending Z command to server:$server port:$port \n";
|
||||
send_zcommand($server,$port,$options['zcommand']);
|
||||
} else {
|
||||
echo "Sending Voxels file:$filename server:$server port:$port command:$command \n";
|
||||
send_voxels($filename,$server,$port,$command);
|
||||
|
|
|
@ -114,6 +114,33 @@ void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) {
|
|||
}
|
||||
}
|
||||
|
||||
void eraseVoxelTreeAndCleanupAgentVisitData() {
|
||||
|
||||
// As our tree to erase all it's voxels
|
||||
::randomTree.eraseAllVoxels();
|
||||
|
||||
// enumerate the agents clean up their marker nodes
|
||||
for (int i = 0; i < agentList.getAgents().size(); i++) {
|
||||
|
||||
//printf("eraseVoxelTreeAndCleanupAgentVisitData() agent[%d]\n",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);
|
||||
|
||||
// clean up the agent visit data
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void *distributeVoxelsToListeners(void *args) {
|
||||
|
||||
timeval lastSendTime;
|
||||
|
@ -133,7 +160,7 @@ void *distributeVoxelsToListeners(void *args) {
|
|||
|
||||
// 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());
|
||||
|
||||
|
@ -319,6 +346,33 @@ int main(int argc, const char * argv[])
|
|||
agentList.broadcastToAgents(packetData,receivedBytes,AgentList::AGENTS_OF_TYPE_HEAD);
|
||||
|
||||
}
|
||||
if (packetData[0] == 'Z') {
|
||||
|
||||
// the Z command is a special command that allows the sender to send the voxel server high level semantic
|
||||
// requests, like erase all, or add sphere scene
|
||||
char* command = &packetData[1]; // start of the command
|
||||
int commandLength = strlen(command); // commands are null terminated strings
|
||||
int totalLength = 1+commandLength+1;
|
||||
|
||||
printf("got Z message len(%ld)= %s\n",receivedBytes,command);
|
||||
|
||||
while (totalLength <= receivedBytes) {
|
||||
if (0==strcmp(command,(char*)"erase all")) {
|
||||
printf("got Z message == erase all\n");
|
||||
|
||||
eraseVoxelTreeAndCleanupAgentVisitData();
|
||||
}
|
||||
if (0==strcmp(command,(char*)"add scene")) {
|
||||
printf("got Z message == add scene\n");
|
||||
addSphereScene(&randomTree,false);
|
||||
}
|
||||
totalLength += commandLength+1;
|
||||
}
|
||||
|
||||
// Now send this to the connected agents so they can also process these messages
|
||||
printf("rebroadcasting Z message to connected agents... agentList.broadcastToAgents()\n");
|
||||
agentList.broadcastToAgents(packetData,receivedBytes,AgentList::AGENTS_OF_TYPE_HEAD);
|
||||
}
|
||||
if (packetData[0] == 'H') {
|
||||
if (agentList.addOrUpdateAgent(&agentPublicAddress,
|
||||
&agentPublicAddress,
|
||||
|
|
Loading…
Reference in a new issue