mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 15:33:10 +02:00
first cut at improved render pipeline
This commit is contained in:
parent
04b29182a8
commit
4f86b5570f
10 changed files with 1222 additions and 237 deletions
941
diff.out
Normal file
941
diff.out
Normal file
|
@ -0,0 +1,941 @@
|
|||
diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp
|
||||
index 24f7665..b8157d0 100644
|
||||
--- a/interface/src/VoxelSystem.cpp
|
||||
+++ b/interface/src/VoxelSystem.cpp
|
||||
@@ -41,69 +41,53 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- .
|
||||
4,5,6, 4,6,7 }; // Z+ .
|
||||
|
||||
VoxelSystem::VoxelSystem() {
|
||||
- voxelsRendered = 0;
|
||||
- tree = new VoxelTree();
|
||||
- pthread_mutex_init(&bufferWriteLock, NULL);
|
||||
+ _voxelsInArrays = _voxelsUpdated = 0;
|
||||
+ _tree = new VoxelTree();
|
||||
+ pthread_mutex_init(&_bufferWriteLock, NULL);
|
||||
}
|
||||
|
||||
VoxelSystem::~VoxelSystem() {
|
||||
- delete[] readVerticesArray;
|
||||
- delete[] writeVerticesArray;
|
||||
- delete[] readColorsArray;
|
||||
- delete[] writeColorsArray;
|
||||
- delete tree;
|
||||
- pthread_mutex_destroy(&bufferWriteLock);
|
||||
+ delete[] _readVerticesArray;
|
||||
+ delete[] _writeVerticesArray;
|
||||
+ delete[] _readColorsArray;
|
||||
+ delete[] _writeColorsArray;
|
||||
+ delete[] _voxelDirtyArray;
|
||||
+ delete _tree;
|
||||
+ pthread_mutex_destroy(&_bufferWriteLock);
|
||||
}
|
||||
|
||||
-//////////////////////////////////////////////////////////////////////////////////////////
|
||||
-// Method: VoxelSystem::loadVoxelsFile()
|
||||
-// Description: Loads HiFidelity encoded Voxels from a binary file. The current file
|
||||
-// format is a stream of single voxels with NO color data. Currently
|
||||
-// colors are set randomly
|
||||
-// Complaints: Brad :)
|
||||
-// To Do: Need to add color data to the file.
|
||||
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
||||
-
|
||||
- tree->loadVoxelsFile(fileName,wantColorRandomizer);
|
||||
-
|
||||
+ _tree->loadVoxelsFile(fileName, wantColorRandomizer);
|
||||
copyWrittenDataToReadArrays();
|
||||
}
|
||||
|
||||
-//////////////////////////////////////////////////////////////////////////////////////////
|
||||
-// Method: VoxelSystem::createSphere()
|
||||
-// Description: Creates a sphere of voxels in the local system at a given location/radius
|
||||
-// To Do: Move this function someplace better? I put it here because we need a
|
||||
-// 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, bool wantColorRandomizer) {
|
||||
-
|
||||
- tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer);
|
||||
+ _tree->createSphere(r, xc, yc, zc, s, solid, wantColorRandomizer);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsCreated() {
|
||||
- return tree->voxelsCreated;
|
||||
+ return _tree->voxelsCreated;
|
||||
}
|
||||
|
||||
float VoxelSystem::getVoxelsCreatedPerSecondAverage() {
|
||||
- return (1 / tree->voxelsCreatedStats.getEventDeltaAverage());
|
||||
+ return (1 / _tree->voxelsCreatedStats.getEventDeltaAverage());
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsColored() {
|
||||
- return tree->voxelsColored;
|
||||
+ return _tree->voxelsColored;
|
||||
}
|
||||
|
||||
float VoxelSystem::getVoxelsColoredPerSecondAverage() {
|
||||
- return (1 / tree->voxelsColoredStats.getEventDeltaAverage());
|
||||
+ return (1 / _tree->voxelsColoredStats.getEventDeltaAverage());
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsBytesRead() {
|
||||
- return tree->voxelsBytesRead;
|
||||
+ return _tree->voxelsBytesRead;
|
||||
}
|
||||
|
||||
float VoxelSystem::getVoxelsBytesReadPerSecondAverage() {
|
||||
- return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond();
|
||||
+ return _tree->voxelsBytesReadStats.getAverageSampleValuePerSecond();
|
||||
}
|
||||
|
||||
int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
@@ -114,11 +98,11 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
switch(command) {
|
||||
case PACKET_HEADER_VOXEL_DATA:
|
||||
// ask the VoxelTree to read the bitstream into the tree
|
||||
- tree->readBitstreamToTree(voxelData, numBytes - 1);
|
||||
+ _tree->readBitstreamToTree(voxelData, numBytes - 1);
|
||||
break;
|
||||
case PACKET_HEADER_ERASE_VOXEL:
|
||||
// ask the tree to read the "remove" bitstream
|
||||
- tree->processRemoveVoxelBitstream(sourceBuffer, numBytes);
|
||||
+ _tree->processRemoveVoxelBitstream(sourceBuffer, numBytes);
|
||||
break;
|
||||
case PACKET_HEADER_Z_COMMAND:
|
||||
|
||||
@@ -135,7 +119,8 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
while (totalLength <= numBytes) {
|
||||
if (0==strcmp(command,(char*)"erase all")) {
|
||||
printLog("got Z message == erase all\n");
|
||||
- tree->eraseAllVoxels();
|
||||
+ _tree->eraseAllVoxels();
|
||||
+ _voxelsInArrays = 0; // better way to do this??
|
||||
}
|
||||
if (0==strcmp(command,(char*)"add scene")) {
|
||||
printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n");
|
||||
@@ -150,78 +135,87 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
}
|
||||
|
||||
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
|
||||
- glm::vec3 treeRoot = glm::vec3(0,0,0);
|
||||
- voxelsRendered = treeToArrays(tree->rootNode, treeRoot);
|
||||
+ _voxelsUpdated = newTreeToArrays(_tree->rootNode);
|
||||
+ if (_voxelsUpdated) {
|
||||
+ _voxelsDirty=true;
|
||||
+ }
|
||||
+
|
||||
// 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);
|
||||
+ if (_voxelsDirty) {
|
||||
+ // lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
||||
+ pthread_mutex_lock(&_bufferWriteLock);
|
||||
+ int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat);
|
||||
+ int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte);
|
||||
+ memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices);
|
||||
+ memcpy(_readColorsArray, _writeColorsArray, bytesOfColors );
|
||||
+ pthread_mutex_unlock(&_bufferWriteLock);
|
||||
+ }
|
||||
}
|
||||
|
||||
-int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosition) {
|
||||
- int voxelsAdded = 0;
|
||||
- float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE);
|
||||
- glm::vec3 viewerPosition = _camera->getPosition(); //_viewerAvatar->getPosition();
|
||||
-
|
||||
- // debug LOD code
|
||||
- glm::vec3 debugNodePosition;
|
||||
- copyFirstVertexForCode(currentNode->octalCode,(float*)&debugNodePosition);
|
||||
-
|
||||
- float distanceToVoxelCenter = sqrtf(powf(viewerPosition.x - nodePosition[0] - halfUnitForVoxel, 2) +
|
||||
- powf(viewerPosition.y - nodePosition[1] - halfUnitForVoxel, 2) +
|
||||
- powf(viewerPosition.z - nodePosition[2] - halfUnitForVoxel, 2));
|
||||
-
|
||||
- int renderLevel = *currentNode->octalCode + 1;
|
||||
- int boundaryPosition = boundaryDistanceForRenderLevel(renderLevel);
|
||||
- bool alwaysDraw = false; // XXXBHG - temporary debug code. Flip this to true to disable LOD blurring
|
||||
-
|
||||
- if (alwaysDraw || distanceToVoxelCenter < boundaryPosition) {
|
||||
- for (int i = 0; i < 8; i++) {
|
||||
- // check if there is a child here
|
||||
- if (currentNode->children[i] != NULL) {
|
||||
-
|
||||
- glm::vec3 childNodePosition;
|
||||
- copyFirstVertexForCode(currentNode->children[i]->octalCode,(float*)&childNodePosition);
|
||||
- childNodePosition *= (float)TREE_SCALE; // scale it up
|
||||
- voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition);
|
||||
- }
|
||||
+int VoxelSystem::newTreeToArrays(VoxelNode* node) {
|
||||
+ assert(_viewFrustum); // you must set up _viewFrustum before calling this
|
||||
+ int voxelsUpdated = 0;
|
||||
+ float distanceToNode = node->distanceToCamera(*_viewFrustum);
|
||||
+ float boundary = boundaryDistanceForRenderLevel(*node->octalCode + 1);
|
||||
+ float childBoundary = boundaryDistanceForRenderLevel(*node->octalCode + 2);
|
||||
+ bool inBoundary = (distanceToNode <= boundary);
|
||||
+ bool inChildBoundary = (distanceToNode <= childBoundary);
|
||||
+ bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary));
|
||||
+
|
||||
+ node->setShouldRender(shouldRender);
|
||||
+ // let children figure out their renderness
|
||||
+ for (int i = 0; i < 8; i++) {
|
||||
+ if (node->children[i]) {
|
||||
+ voxelsUpdated += newTreeToArrays(node->children[i]);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us
|
||||
+ if (node->isDirty() && (shouldRender || node->isKnownBufferIndex())) {
|
||||
+ glm::vec3 startVertex;
|
||||
+ float voxelScale = 0;
|
||||
+
|
||||
+ // If we're should render, use our legit location and scale,
|
||||
+ if (node->getShouldRender()) {
|
||||
+ copyFirstVertexForCode(node->octalCode, (float*)&startVertex);
|
||||
+ voxelScale = (1 / powf(2, *node->octalCode));
|
||||
+ } else {
|
||||
+ // if we shouldn't render then set out location to some infinitely distant location,
|
||||
+ // and our scale as infinitely small
|
||||
+ startVertex[0] = startVertex[1] = startVertex[2] = FLT_MAX;
|
||||
+ voxelScale = 0;
|
||||
+ }
|
||||
|
||||
- // 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->isColored()) {
|
||||
- float startVertex[3];
|
||||
- copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex);
|
||||
- float voxelScale = 1 / powf(2, *currentNode->octalCode);
|
||||
+ // If this node has not yet been written to the array, then add it to the end of the array.
|
||||
+ glBufferIndex nodeIndex;
|
||||
+ if (node->isKnownBufferIndex()) {
|
||||
+ nodeIndex = node->getBufferIndex();
|
||||
+ } else {
|
||||
+ nodeIndex = _voxelsInArrays;
|
||||
+ }
|
||||
+
|
||||
+ _voxelDirtyArray[nodeIndex] = true;
|
||||
|
||||
// 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++ ) {
|
||||
- *writeVerticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||
- *(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->getColor()[j % 3];
|
||||
-
|
||||
- writeVerticesEndPointer++;
|
||||
+ GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
+ GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
+ *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||
+ *(writeColorsAt +j) = node->getColor()[j % 3];
|
||||
+ }
|
||||
+ if (!node->isKnownBufferIndex()) {
|
||||
+ node->setBufferIndex(nodeIndex);
|
||||
+ _voxelsInArrays++; // our know vertices in the arrays
|
||||
}
|
||||
- voxelsAdded++;
|
||||
+ voxelsUpdated++;
|
||||
+ node->clearDirtyBit();
|
||||
}
|
||||
-
|
||||
- return voxelsAdded;
|
||||
+ return voxelsUpdated;
|
||||
}
|
||||
|
||||
VoxelSystem* VoxelSystem::clone() const {
|
||||
@@ -230,20 +224,30 @@ VoxelSystem* VoxelSystem::clone() const {
|
||||
}
|
||||
|
||||
void VoxelSystem::init() {
|
||||
+
|
||||
+ // When we change voxels representations in the arrays, we'll update this
|
||||
+ _voxelsDirty = false;
|
||||
+ _voxelsInArrays = 0;
|
||||
+
|
||||
+ // we will track individual dirty sections with this array of bools
|
||||
+ _voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM];
|
||||
+ memset(_voxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool));
|
||||
+
|
||||
// prep the data structures for incoming voxel data
|
||||
- writeVerticesEndPointer = writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
- readVerticesEndPointer = 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];
|
||||
+ _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];
|
||||
+ GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
|
||||
// populate the indicesArray
|
||||
// this will not change given new voxels, so we can set it all up now
|
||||
for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) {
|
||||
// fill the indices array
|
||||
int voxelIndexOffset = n * INDICES_PER_VOXEL;
|
||||
- GLuint *currentIndicesPos = indicesArray + voxelIndexOffset;
|
||||
+ GLuint* currentIndicesPos = indicesArray + voxelIndexOffset;
|
||||
int startIndex = (n * VERTICES_PER_VOXEL);
|
||||
|
||||
for (int i = 0; i < INDICES_PER_VOXEL; i++) {
|
||||
@@ -252,8 +256,8 @@ void VoxelSystem::init() {
|
||||
}
|
||||
}
|
||||
|
||||
- GLfloat *normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
- GLfloat *normalsArrayEndPointer = normalsArray;
|
||||
+ GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
+ GLfloat* normalsArrayEndPointer = normalsArray;
|
||||
|
||||
// populate the normalsArray
|
||||
for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) {
|
||||
@@ -263,25 +267,25 @@ void VoxelSystem::init() {
|
||||
}
|
||||
|
||||
// VBO for the verticesArray
|
||||
- glGenBuffers(1, &vboVerticesID);
|
||||
- glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
+ glGenBuffers(1, &_vboVerticesID);
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
// VBO for the normalsArray
|
||||
- glGenBuffers(1, &vboNormalsID);
|
||||
- glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
|
||||
+ glGenBuffers(1, &_vboNormalsID);
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM,
|
||||
normalsArray, GL_STATIC_DRAW);
|
||||
|
||||
// VBO for colorsArray
|
||||
- glGenBuffers(1, &vboColorsID);
|
||||
- glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
+ glGenBuffers(1, &_vboColorsID);
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
// VBO for the indicesArray
|
||||
- glGenBuffers(1, &vboIndicesID);
|
||||
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
|
||||
+ 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);
|
||||
@@ -291,45 +295,68 @@ void VoxelSystem::init() {
|
||||
delete[] normalsArray;
|
||||
}
|
||||
|
||||
-void VoxelSystem::render() {
|
||||
-
|
||||
- glPushMatrix();
|
||||
-
|
||||
- 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);
|
||||
- glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLfloat), readVerticesArray);
|
||||
-
|
||||
- glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
- glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLubyte), readColorsArray);
|
||||
-
|
||||
- readVerticesEndPointer = readVerticesArray;
|
||||
-
|
||||
- pthread_mutex_unlock(&bufferWriteLock);
|
||||
+void VoxelSystem::updateVBOs() {
|
||||
+ if (_voxelsDirty) {
|
||||
+ glBufferIndex segmentStart = 0;
|
||||
+ glBufferIndex segmentEnd = 0;
|
||||
+
|
||||
+ bool inSegment = false;
|
||||
+ for (glBufferIndex i = 0; i < _voxelsInArrays; i++) {
|
||||
+ if (!inSegment) {
|
||||
+ if (_voxelDirtyArray[i]) {
|
||||
+ segmentStart = i;
|
||||
+ inSegment = true;
|
||||
+ _voxelDirtyArray[i] = false; // consider us clean!
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) {
|
||||
+ segmentEnd = i;
|
||||
+ inSegment = false;
|
||||
+ int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||
+
|
||||
+ // vertices for segment - note: we might not need to do this
|
||||
+ GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
||||
+ GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
||||
+ GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
+
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
+ glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||
+
|
||||
+ // colors for segment
|
||||
+ segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
+ segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
+ GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
+
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
+ glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
+ _voxelsDirty = false;
|
||||
}
|
||||
+}
|
||||
|
||||
+void VoxelSystem::render() {
|
||||
+ glPushMatrix();
|
||||
+ updateVBOs();
|
||||
// tell OpenGL where to find vertex and color information
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
- glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
|
||||
- glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||
glNormalPointer(GL_FLOAT, 0, 0);
|
||||
|
||||
- glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
+ glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||
|
||||
// draw the number of voxels we have
|
||||
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
|
||||
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
||||
glScalef(10, 10, 10);
|
||||
- glDrawElements(GL_TRIANGLES, 36 * voxelsRendered, GL_UNSIGNED_INT, 0);
|
||||
+ glDrawElements(GL_TRIANGLES, 36 * _voxelsInArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
// deactivate vertex and color arrays after drawing
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
@@ -350,12 +377,7 @@ void VoxelSystem::simulate(float deltaTime) {
|
||||
|
||||
int VoxelSystem::_nodeCount = 0;
|
||||
|
||||
-bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
-
|
||||
- // we do our operations on the way up!
|
||||
- if (down) {
|
||||
- return true;
|
||||
- }
|
||||
+bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {
|
||||
|
||||
_nodeCount++;
|
||||
if (node->isColored()) {
|
||||
@@ -370,17 +392,12 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraDa
|
||||
|
||||
void VoxelSystem::randomizeVoxelColors() {
|
||||
_nodeCount = 0;
|
||||
- tree->recurseTreeWithOperation(randomColorOperation);
|
||||
+ _tree->recurseTreeWithOperation(randomColorOperation);
|
||||
printLog("setting randomized true color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
-bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
-
|
||||
- // we do our operations on the way up!
|
||||
- if (down) {
|
||||
- return true;
|
||||
- }
|
||||
+bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData) {
|
||||
|
||||
_nodeCount++;
|
||||
|
||||
@@ -395,18 +412,12 @@ bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void*
|
||||
|
||||
void VoxelSystem::falseColorizeRandom() {
|
||||
_nodeCount = 0;
|
||||
- tree->recurseTreeWithOperation(falseColorizeRandomOperation);
|
||||
+ _tree->recurseTreeWithOperation(falseColorizeRandomOperation);
|
||||
printLog("setting randomized false color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
-bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
-
|
||||
- // we do our operations on the way up!
|
||||
- if (down) {
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
+bool VoxelSystem::trueColorizeOperation(VoxelNode* node, void* extraData) {
|
||||
_nodeCount++;
|
||||
node->setFalseColored(false);
|
||||
return true;
|
||||
@@ -414,19 +425,13 @@ bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraD
|
||||
|
||||
void VoxelSystem::trueColorize() {
|
||||
_nodeCount = 0;
|
||||
- tree->recurseTreeWithOperation(trueColorizeOperation);
|
||||
+ _tree->recurseTreeWithOperation(trueColorizeOperation);
|
||||
printLog("setting true color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
// Will false colorize voxels that are not in view
|
||||
-bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
-
|
||||
- // we do our operations on the way up!
|
||||
- if (down) {
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
+bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, void* extraData) {
|
||||
const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData;
|
||||
|
||||
_nodeCount++;
|
||||
@@ -448,25 +453,17 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void*
|
||||
|
||||
void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) {
|
||||
_nodeCount = 0;
|
||||
- tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
|
||||
+ _tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
|
||||
printLog("setting in view false color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
// Will false colorize voxels based on distance from view
|
||||
-bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
-
|
||||
- // we do our operations on the way up!
|
||||
- if (down) {
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
+bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData) {
|
||||
ViewFrustum* viewFrustum = (ViewFrustum*) extraData;
|
||||
|
||||
// only do this for truly colored voxels...
|
||||
if (node->isColored()) {
|
||||
-
|
||||
- // We need our distance for both up and down
|
||||
glm::vec3 nodePosition;
|
||||
float* startVertex = firstVertexForCode(node->octalCode);
|
||||
nodePosition.x = startVertex[0];
|
||||
@@ -508,13 +505,7 @@ float VoxelSystem::_minDistance = FLT_MAX;
|
||||
// Helper function will get the distance from view range, would be nice if you could just keep track
|
||||
// of this as voxels are created and/or colored... seems like some transform math could do that so
|
||||
// we wouldn't need to do two passes of the tree
|
||||
-bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
-
|
||||
- // we do our operations on the way up!
|
||||
- if (down) {
|
||||
- return true;
|
||||
- }
|
||||
-
|
||||
+bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData) {
|
||||
ViewFrustum* viewFrustum = (ViewFrustum*) extraData;
|
||||
|
||||
// only do this for truly colored voxels...
|
||||
@@ -538,7 +529,7 @@ bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down,
|
||||
powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) +
|
||||
powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2));
|
||||
|
||||
- // on way down, calculate the range of distances
|
||||
+ // calculate the range of distances
|
||||
if (distance > _maxDistance) {
|
||||
_maxDistance = distance;
|
||||
}
|
||||
@@ -556,12 +547,14 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) {
|
||||
|
||||
_maxDistance = 0.0;
|
||||
_minDistance = FLT_MAX;
|
||||
- tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);
|
||||
+ _tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);
|
||||
printLog("determining distance range for %d nodes\n",_nodeCount);
|
||||
|
||||
_nodeCount = 0;
|
||||
|
||||
- tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
|
||||
+ _tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
|
||||
printLog("setting in distance false color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
+
|
||||
+
|
||||
diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h
|
||||
index f12cc75..04f9f8c 100644
|
||||
--- a/interface/src/VoxelSystem.h
|
||||
+++ b/interface/src/VoxelSystem.h
|
||||
@@ -29,12 +29,16 @@ public:
|
||||
|
||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||
VoxelSystem* clone() const;
|
||||
+
|
||||
+ void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; };
|
||||
|
||||
void init();
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
- void setVoxelsRendered(int v) {voxelsRendered = v;};
|
||||
- int getVoxelsRendered() {return voxelsRendered;};
|
||||
+
|
||||
+ unsigned long getVoxelsUpdated() const {return _voxelsUpdated;};
|
||||
+ unsigned long getVoxelsRendered() const {return _voxelsInArrays;};
|
||||
+
|
||||
void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; };
|
||||
void setCamera(Camera* newCamera) { _camera = newCamera; };
|
||||
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
|
||||
@@ -57,36 +61,42 @@ public:
|
||||
private:
|
||||
// Operation functions for tree recursion methods
|
||||
static int _nodeCount;
|
||||
- static bool randomColorOperation(VoxelNode* node, bool down, void* extraData);
|
||||
- static bool falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData);
|
||||
- static bool trueColorizeOperation(VoxelNode* node, bool down, void* extraData);
|
||||
- static bool falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData);
|
||||
- static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData);
|
||||
- static bool getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData);
|
||||
+ static bool randomColorOperation(VoxelNode* node, void* extraData);
|
||||
+ static bool falseColorizeRandomOperation(VoxelNode* node, void* extraData);
|
||||
+ static bool trueColorizeOperation(VoxelNode* node, void* extraData);
|
||||
+ static bool falseColorizeInViewOperation(VoxelNode* node, void* extraData);
|
||||
+ static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData);
|
||||
+ static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData);
|
||||
|
||||
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
|
||||
static float _maxDistance;
|
||||
static float _minDistance;
|
||||
|
||||
- int voxelsRendered;
|
||||
Avatar* _viewerAvatar;
|
||||
Camera* _camera;
|
||||
- VoxelTree *tree;
|
||||
- GLfloat *readVerticesArray;
|
||||
- GLubyte *readColorsArray;
|
||||
- GLfloat *readVerticesEndPointer;
|
||||
- GLfloat *writeVerticesArray;
|
||||
- GLubyte *writeColorsArray;
|
||||
- GLfloat *writeVerticesEndPointer;
|
||||
- GLuint vboVerticesID;
|
||||
- GLuint vboNormalsID;
|
||||
- GLuint vboColorsID;
|
||||
- GLuint vboIndicesID;
|
||||
- pthread_mutex_t bufferWriteLock;
|
||||
-
|
||||
- int treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosition);
|
||||
+ VoxelTree* _tree;
|
||||
+ GLfloat* _readVerticesArray;
|
||||
+ GLubyte* _readColorsArray;
|
||||
+ GLfloat* _writeVerticesArray;
|
||||
+ GLubyte* _writeColorsArray;
|
||||
+ bool* _voxelDirtyArray;
|
||||
+ unsigned long _voxelsUpdated;
|
||||
+ unsigned long _voxelsInArrays;
|
||||
+
|
||||
+ GLuint _vboVerticesID;
|
||||
+ GLuint _vboNormalsID;
|
||||
+ GLuint _vboColorsID;
|
||||
+ GLuint _vboIndicesID;
|
||||
+ pthread_mutex_t _bufferWriteLock;
|
||||
+
|
||||
+ ViewFrustum* _viewFrustum;
|
||||
+
|
||||
+ int newTreeToArrays(VoxelNode *currentNode);
|
||||
void setupNewVoxelsForDrawing();
|
||||
void copyWrittenDataToReadArrays();
|
||||
+ void updateVBOs();
|
||||
+
|
||||
+ bool _voxelsDirty;
|
||||
};
|
||||
|
||||
#endif
|
||||
diff --git a/interface/src/main.cpp b/interface/src/main.cpp
|
||||
index 7ef1c49..b73d58f 100644
|
||||
--- a/interface/src/main.cpp
|
||||
+++ b/interface/src/main.cpp
|
||||
@@ -230,7 +230,7 @@ void displayStats(void)
|
||||
drawtext(10, statsVerticalOffset + 49, 0.10f, 0, 1.0, 0, stats);
|
||||
|
||||
std::stringstream voxelStats;
|
||||
- voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered();
|
||||
+ voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered() << " Updated: " << voxels.getVoxelsUpdated();
|
||||
drawtext(10, statsVerticalOffset + 70, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
@@ -1612,6 +1612,8 @@ void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) {
|
||||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
+ voxels.setViewFrustum(&::viewFrustum);
|
||||
+
|
||||
shared_lib::printLog = & ::printLog;
|
||||
voxels_lib::printLog = & ::printLog;
|
||||
avatars_lib::printLog = & ::printLog;
|
||||
@@ -1634,7 +1636,7 @@ int main(int argc, const char * argv[])
|
||||
}
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
- if (cmdOptionExists(argc, argv, "--local")) {
|
||||
+ if (true || cmdOptionExists(argc, argv, "--local")) {
|
||||
printLog("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));
|
||||
diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h
|
||||
index 66ddbcb..2ba4d05 100644
|
||||
--- a/libraries/voxels/src/VoxelConstants.h
|
||||
+++ b/libraries/voxels/src/VoxelConstants.h
|
||||
@@ -21,4 +21,7 @@ const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
||||
const int INDICES_PER_VOXEL = 3 * 12;
|
||||
const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
||||
|
||||
+typedef unsigned long int glBufferIndex;
|
||||
+const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
|
||||
+
|
||||
#endif
|
||||
diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp
|
||||
index c1527d3..6f8f1d7 100644
|
||||
--- a/libraries/voxels/src/VoxelNode.cpp
|
||||
+++ b/libraries/voxels/src/VoxelNode.cpp
|
||||
@@ -30,6 +30,10 @@ VoxelNode::VoxelNode() {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
children[i] = NULL;
|
||||
}
|
||||
+
|
||||
+ _glBufferIndex = GLBUFFER_INDEX_UNKNOWN;
|
||||
+ _isDirty = true;
|
||||
+ _shouldRender = false;
|
||||
}
|
||||
|
||||
VoxelNode::~VoxelNode() {
|
||||
@@ -43,6 +47,14 @@ VoxelNode::~VoxelNode() {
|
||||
}
|
||||
}
|
||||
|
||||
+void VoxelNode::setShouldRender(bool shouldRender) {
|
||||
+ // if shouldRender is changing, then consider ourselves dirty
|
||||
+ if (shouldRender != _shouldRender) {
|
||||
+ _shouldRender = shouldRender;
|
||||
+ _isDirty = true;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void VoxelNode::getAABox(AABox& box) const {
|
||||
|
||||
glm::vec3 corner;
|
||||
@@ -59,16 +71,19 @@ void VoxelNode::getAABox(AABox& box) const {
|
||||
}
|
||||
|
||||
void VoxelNode::addChildAtIndex(int childIndex) {
|
||||
- children[childIndex] = new VoxelNode();
|
||||
+ if (!children[childIndex]) {
|
||||
+ children[childIndex] = new VoxelNode();
|
||||
|
||||
- // XXXBHG - When the node is constructed, it should be cleanly set up as
|
||||
- // true colored, but for some reason, not so much. I've added a a basecamp
|
||||
- // to-do to research this. But for now we'll use belt and suspenders and set
|
||||
- // it to not-false-colored here!
|
||||
- children[childIndex]->setFalseColored(false);
|
||||
+ // XXXBHG - When the node is constructed, it should be cleanly set up as
|
||||
+ // true colored, but for some reason, not so much. I've added a a basecamp
|
||||
+ // to-do to research this. But for now we'll use belt and suspenders and set
|
||||
+ // it to not-false-colored here!
|
||||
+ children[childIndex]->setFalseColored(false);
|
||||
|
||||
- // give this child its octal code
|
||||
- children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
|
||||
+ // give this child its octal code
|
||||
+ children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
|
||||
+ _isDirty = true;
|
||||
+ }
|
||||
}
|
||||
|
||||
// will average the child colors...
|
||||
@@ -104,26 +119,35 @@ void VoxelNode::setColorFromAverageOfChildren() {
|
||||
// the actual NO_FALSE_COLOR version are inline in the VoxelNode.h
|
||||
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
||||
void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) {
|
||||
- _falseColored=true;
|
||||
- _currentColor[0] = red;
|
||||
- _currentColor[1] = green;
|
||||
- _currentColor[2] = blue;
|
||||
- _currentColor[3] = 1; // XXXBHG - False colors are always considered set
|
||||
+ if (_falseColored != true || _currentColor[0] != red || _currentColor[1] != green || _currentColor[2] != blue) {
|
||||
+ _falseColored=true;
|
||||
+ _currentColor[0] = red;
|
||||
+ _currentColor[1] = green;
|
||||
+ _currentColor[2] = blue;
|
||||
+ _currentColor[3] = 1; // XXXBHG - False colors are always considered set
|
||||
+ _isDirty = true;
|
||||
+ }
|
||||
}
|
||||
|
||||
void VoxelNode::setFalseColored(bool isFalseColored) {
|
||||
- // if we were false colored, and are no longer false colored, then swap back
|
||||
- if (_falseColored && !isFalseColored) {
|
||||
- memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
|
||||
+ if (_falseColored != isFalseColored) {
|
||||
+ // if we were false colored, and are no longer false colored, then swap back
|
||||
+ if (_falseColored && !isFalseColored) {
|
||||
+ memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
|
||||
+ }
|
||||
+ _falseColored = isFalseColored;
|
||||
+ _isDirty = true;
|
||||
}
|
||||
- _falseColored = isFalseColored;
|
||||
};
|
||||
|
||||
|
||||
void VoxelNode::setColor(const nodeColor& color) {
|
||||
- memcpy(&_trueColor,&color,sizeof(nodeColor));
|
||||
- if (!_falseColored) {
|
||||
- memcpy(&_currentColor,&color,sizeof(nodeColor));
|
||||
+ if (_trueColor[0] != color[0] || _trueColor[1] != color[1] || _trueColor[2] != color[2]) {
|
||||
+ memcpy(&_trueColor,&color,sizeof(nodeColor));
|
||||
+ if (!_falseColored) {
|
||||
+ memcpy(&_currentColor,&color,sizeof(nodeColor));
|
||||
+ }
|
||||
+ _isDirty = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -199,7 +223,6 @@ void VoxelNode::printDebugDetails(const char* label) const {
|
||||
printOctalCode(octalCode);
|
||||
}
|
||||
|
||||
-
|
||||
bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const {
|
||||
AABox box;
|
||||
getAABox(box);
|
||||
diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h
|
||||
index 4cda55f..cbd9b8a 100644
|
||||
--- a/libraries/voxels/src/VoxelNode.h
|
||||
+++ b/libraries/voxels/src/VoxelNode.h
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "AABox.h"
|
||||
#include "ViewFrustum.h"
|
||||
+#include "VoxelConstants.h"
|
||||
|
||||
typedef unsigned char colorPart;
|
||||
typedef unsigned char nodeColor[4];
|
||||
@@ -22,6 +23,11 @@ private:
|
||||
nodeColor _currentColor;
|
||||
bool _falseColored;
|
||||
#endif
|
||||
+
|
||||
+ glBufferIndex _glBufferIndex;
|
||||
+ bool _isDirty;
|
||||
+ bool _shouldRender;
|
||||
+
|
||||
public:
|
||||
VoxelNode();
|
||||
~VoxelNode();
|
||||
@@ -40,6 +46,18 @@ public:
|
||||
bool isLeaf() const;
|
||||
void getAABox(AABox& box) const;
|
||||
void printDebugDetails(const char* label) const;
|
||||
+
|
||||
+ bool isDirty() const { return _isDirty; };
|
||||
+ void clearDirtyBit() { _isDirty = false; };
|
||||
+
|
||||
+ glBufferIndex getBufferIndex() const { return _glBufferIndex; };
|
||||
+ bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); };
|
||||
+ void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; };
|
||||
+
|
||||
+ // whether or not we should render
|
||||
+ void setShouldRender(bool shouldRender);
|
||||
+ bool getShouldRender() const { return _shouldRender; }
|
||||
+
|
||||
|
||||
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
||||
void setFalseColor(colorPart red, colorPart green, colorPart blue);
|
||||
diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp
|
||||
index cbbcced..3ff14b5 100644
|
||||
--- a/libraries/voxels/src/VoxelTree.cpp
|
||||
+++ b/libraries/voxels/src/VoxelTree.cpp
|
||||
@@ -58,16 +58,13 @@ void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, vo
|
||||
|
||||
// Recurses voxel node with an operation function
|
||||
void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData) {
|
||||
- // call the operation function going "down" first, stop deeper recursion if function returns false
|
||||
- if (operation(node,true,extraData)) {
|
||||
- for (int i = 0; i < sizeof(node->children)/sizeof(node->children[0]); i++) {
|
||||
+ if (operation(node, extraData)) {
|
||||
+ for (int i = 0; i < sizeof(node->children) / sizeof(node->children[0]); i++) {
|
||||
VoxelNode* child = node->children[i];
|
||||
if (child) {
|
||||
- recurseNodeWithOperation(child,operation,extraData);
|
||||
+ recurseNodeWithOperation(child, operation, extraData);
|
||||
}
|
||||
}
|
||||
- // call operation on way back up
|
||||
- operation(node,false,extraData);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h
|
||||
index ac3c762..7f5a6b8 100644
|
||||
--- a/libraries/voxels/src/VoxelTree.h
|
||||
+++ b/libraries/voxels/src/VoxelTree.h
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "VoxelNodeBag.h"
|
||||
|
||||
// Callback function, for recuseTreeWithOperation
|
||||
-typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData);
|
||||
+typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData);
|
||||
|
||||
class VoxelTree {
|
||||
public:
|
||||
diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp
|
||||
index 716a4e9..9ab5675 100644
|
||||
--- a/voxel-server/src/main.cpp
|
||||
+++ b/voxel-server/src/main.cpp
|
||||
@@ -38,7 +38,7 @@ const float DEATH_STAR_RADIUS = 4.0;
|
||||
const float MAX_CUBE = 0.05f;
|
||||
|
||||
const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000;
|
||||
-const int PACKETS_PER_CLIENT_PER_INTERVAL = 2;
|
||||
+const int PACKETS_PER_CLIENT_PER_INTERVAL = 20;
|
||||
|
||||
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
|
||||
|
||||
@@ -68,11 +68,9 @@ void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) {
|
||||
}
|
||||
|
||||
int _nodeCount=0;
|
||||
-bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
- if (down) {
|
||||
- if (node->isColored()){
|
||||
- _nodeCount++;
|
||||
- }
|
||||
+bool countVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||
+ if (node->isColored()){
|
||||
+ _nodeCount++;
|
||||
}
|
||||
return true; // keep going
|
||||
}
|
||||
@@ -80,7 +78,7 @@ bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) {
|
||||
printf("adding scene of spheres...\n");
|
||||
|
||||
- int sphereBaseSize = 256;
|
||||
+ int sphereBaseSize = 512;
|
||||
|
||||
tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, wantColorRandomizer);
|
||||
printf("one sphere added...\n");
|
|
@ -41,69 +41,53 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- .
|
|||
4,5,6, 4,6,7 }; // Z+ .
|
||||
|
||||
VoxelSystem::VoxelSystem() {
|
||||
voxelsRendered = 0;
|
||||
tree = new VoxelTree();
|
||||
pthread_mutex_init(&bufferWriteLock, NULL);
|
||||
_voxelsInArrays = _voxelsUpdated = 0;
|
||||
_tree = new VoxelTree();
|
||||
pthread_mutex_init(&_bufferWriteLock, NULL);
|
||||
}
|
||||
|
||||
VoxelSystem::~VoxelSystem() {
|
||||
delete[] readVerticesArray;
|
||||
delete[] writeVerticesArray;
|
||||
delete[] readColorsArray;
|
||||
delete[] writeColorsArray;
|
||||
delete tree;
|
||||
pthread_mutex_destroy(&bufferWriteLock);
|
||||
delete[] _readVerticesArray;
|
||||
delete[] _writeVerticesArray;
|
||||
delete[] _readColorsArray;
|
||||
delete[] _writeColorsArray;
|
||||
delete[] _voxelDirtyArray;
|
||||
delete _tree;
|
||||
pthread_mutex_destroy(&_bufferWriteLock);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Method: VoxelSystem::loadVoxelsFile()
|
||||
// Description: Loads HiFidelity encoded Voxels from a binary file. The current file
|
||||
// format is a stream of single voxels with NO color data. Currently
|
||||
// colors are set randomly
|
||||
// Complaints: Brad :)
|
||||
// To Do: Need to add color data to the file.
|
||||
void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
|
||||
|
||||
tree->loadVoxelsFile(fileName,wantColorRandomizer);
|
||||
|
||||
_tree->loadVoxelsFile(fileName, wantColorRandomizer);
|
||||
copyWrittenDataToReadArrays();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Method: VoxelSystem::createSphere()
|
||||
// Description: Creates a sphere of voxels in the local system at a given location/radius
|
||||
// To Do: Move this function someplace better? I put it here because we need a
|
||||
// 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, bool wantColorRandomizer) {
|
||||
|
||||
tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer);
|
||||
_tree->createSphere(r, xc, yc, zc, s, solid, wantColorRandomizer);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsCreated() {
|
||||
return tree->voxelsCreated;
|
||||
return _tree->voxelsCreated;
|
||||
}
|
||||
|
||||
float VoxelSystem::getVoxelsCreatedPerSecondAverage() {
|
||||
return (1 / tree->voxelsCreatedStats.getEventDeltaAverage());
|
||||
return (1 / _tree->voxelsCreatedStats.getEventDeltaAverage());
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsColored() {
|
||||
return tree->voxelsColored;
|
||||
return _tree->voxelsColored;
|
||||
}
|
||||
|
||||
float VoxelSystem::getVoxelsColoredPerSecondAverage() {
|
||||
return (1 / tree->voxelsColoredStats.getEventDeltaAverage());
|
||||
return (1 / _tree->voxelsColoredStats.getEventDeltaAverage());
|
||||
}
|
||||
|
||||
long int VoxelSystem::getVoxelsBytesRead() {
|
||||
return tree->voxelsBytesRead;
|
||||
return _tree->voxelsBytesRead;
|
||||
}
|
||||
|
||||
float VoxelSystem::getVoxelsBytesReadPerSecondAverage() {
|
||||
return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond();
|
||||
return _tree->voxelsBytesReadStats.getAverageSampleValuePerSecond();
|
||||
}
|
||||
|
||||
int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||
|
@ -114,11 +98,11 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
switch(command) {
|
||||
case PACKET_HEADER_VOXEL_DATA:
|
||||
// ask the VoxelTree to read the bitstream into the tree
|
||||
tree->readBitstreamToTree(voxelData, numBytes - 1);
|
||||
_tree->readBitstreamToTree(voxelData, numBytes - 1);
|
||||
break;
|
||||
case PACKET_HEADER_ERASE_VOXEL:
|
||||
// ask the tree to read the "remove" bitstream
|
||||
tree->processRemoveVoxelBitstream(sourceBuffer, numBytes);
|
||||
_tree->processRemoveVoxelBitstream(sourceBuffer, numBytes);
|
||||
break;
|
||||
case PACKET_HEADER_Z_COMMAND:
|
||||
|
||||
|
@ -135,7 +119,8 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
while (totalLength <= numBytes) {
|
||||
if (0==strcmp(command,(char*)"erase all")) {
|
||||
printLog("got Z message == erase all\n");
|
||||
tree->eraseAllVoxels();
|
||||
_tree->eraseAllVoxels();
|
||||
_voxelsInArrays = 0; // better way to do this??
|
||||
}
|
||||
if (0==strcmp(command,(char*)"add scene")) {
|
||||
printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n");
|
||||
|
@ -150,78 +135,87 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
|||
}
|
||||
|
||||
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
|
||||
glm::vec3 treeRoot = glm::vec3(0,0,0);
|
||||
voxelsRendered = treeToArrays(tree->rootNode, treeRoot);
|
||||
_voxelsUpdated = newTreeToArrays(_tree->rootNode);
|
||||
if (_voxelsUpdated) {
|
||||
_voxelsDirty=true;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (_voxelsDirty) {
|
||||
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
|
||||
pthread_mutex_lock(&_bufferWriteLock);
|
||||
int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat);
|
||||
int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte);
|
||||
memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices);
|
||||
memcpy(_readColorsArray, _writeColorsArray, bytesOfColors );
|
||||
pthread_mutex_unlock(&_bufferWriteLock);
|
||||
}
|
||||
}
|
||||
|
||||
int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosition) {
|
||||
int voxelsAdded = 0;
|
||||
float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE);
|
||||
glm::vec3 viewerPosition = _camera->getPosition(); //_viewerAvatar->getPosition();
|
||||
int VoxelSystem::newTreeToArrays(VoxelNode* node) {
|
||||
assert(_viewFrustum); // you must set up _viewFrustum before calling this
|
||||
int voxelsUpdated = 0;
|
||||
float distanceToNode = node->distanceToCamera(*_viewFrustum);
|
||||
float boundary = boundaryDistanceForRenderLevel(*node->octalCode + 1);
|
||||
float childBoundary = boundaryDistanceForRenderLevel(*node->octalCode + 2);
|
||||
bool inBoundary = (distanceToNode <= boundary);
|
||||
bool inChildBoundary = (distanceToNode <= childBoundary);
|
||||
bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary));
|
||||
|
||||
// debug LOD code
|
||||
glm::vec3 debugNodePosition;
|
||||
copyFirstVertexForCode(currentNode->octalCode,(float*)&debugNodePosition);
|
||||
|
||||
float distanceToVoxelCenter = sqrtf(powf(viewerPosition.x - nodePosition[0] - halfUnitForVoxel, 2) +
|
||||
powf(viewerPosition.y - nodePosition[1] - halfUnitForVoxel, 2) +
|
||||
powf(viewerPosition.z - nodePosition[2] - halfUnitForVoxel, 2));
|
||||
|
||||
int renderLevel = *currentNode->octalCode + 1;
|
||||
int boundaryPosition = boundaryDistanceForRenderLevel(renderLevel);
|
||||
bool alwaysDraw = false; // XXXBHG - temporary debug code. Flip this to true to disable LOD blurring
|
||||
|
||||
if (alwaysDraw || distanceToVoxelCenter < boundaryPosition) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// check if there is a child here
|
||||
if (currentNode->children[i] != NULL) {
|
||||
|
||||
glm::vec3 childNodePosition;
|
||||
copyFirstVertexForCode(currentNode->children[i]->octalCode,(float*)&childNodePosition);
|
||||
childNodePosition *= (float)TREE_SCALE; // scale it up
|
||||
voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition);
|
||||
}
|
||||
node->setShouldRender(shouldRender);
|
||||
// let children figure out their renderness
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (node->children[i]) {
|
||||
voxelsUpdated += newTreeToArrays(node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us
|
||||
if (node->isDirty() && (shouldRender || node->isKnownBufferIndex())) {
|
||||
glm::vec3 startVertex;
|
||||
float voxelScale = 0;
|
||||
|
||||
// If we're should render, use our legit location and scale,
|
||||
if (node->getShouldRender()) {
|
||||
copyFirstVertexForCode(node->octalCode, (float*)&startVertex);
|
||||
voxelScale = (1 / powf(2, *node->octalCode));
|
||||
} else {
|
||||
// if we shouldn't render then set out location to some infinitely distant location,
|
||||
// and our scale as infinitely small
|
||||
startVertex[0] = startVertex[1] = startVertex[2] = FLT_MAX;
|
||||
voxelScale = 0;
|
||||
}
|
||||
|
||||
// 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->isColored()) {
|
||||
float startVertex[3];
|
||||
copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex);
|
||||
float voxelScale = 1 / powf(2, *currentNode->octalCode);
|
||||
// If this node has not yet been written to the array, then add it to the end of the array.
|
||||
glBufferIndex nodeIndex;
|
||||
if (node->isKnownBufferIndex()) {
|
||||
nodeIndex = node->getBufferIndex();
|
||||
} else {
|
||||
nodeIndex = _voxelsInArrays;
|
||||
}
|
||||
|
||||
_voxelDirtyArray[nodeIndex] = true;
|
||||
|
||||
// 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++ ) {
|
||||
*writeVerticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||
*(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->getColor()[j % 3];
|
||||
|
||||
writeVerticesEndPointer++;
|
||||
GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL);
|
||||
*(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale);
|
||||
*(writeColorsAt +j) = node->getColor()[j % 3];
|
||||
}
|
||||
voxelsAdded++;
|
||||
if (!node->isKnownBufferIndex()) {
|
||||
node->setBufferIndex(nodeIndex);
|
||||
_voxelsInArrays++; // our know vertices in the arrays
|
||||
}
|
||||
voxelsUpdated++;
|
||||
node->clearDirtyBit();
|
||||
}
|
||||
|
||||
return voxelsAdded;
|
||||
return voxelsUpdated;
|
||||
}
|
||||
|
||||
VoxelSystem* VoxelSystem::clone() const {
|
||||
|
@ -230,20 +224,30 @@ VoxelSystem* VoxelSystem::clone() const {
|
|||
}
|
||||
|
||||
void VoxelSystem::init() {
|
||||
// prep the data structures for incoming voxel data
|
||||
writeVerticesEndPointer = writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
readVerticesEndPointer = 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];
|
||||
// When we change voxels representations in the arrays, we'll update this
|
||||
_voxelsDirty = false;
|
||||
_voxelsInArrays = 0;
|
||||
|
||||
// we will track individual dirty sections with this array of bools
|
||||
_voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM];
|
||||
memset(_voxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool));
|
||||
|
||||
// prep the data structures for incoming voxel data
|
||||
_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];
|
||||
|
||||
// populate the indicesArray
|
||||
// this will not change given new voxels, so we can set it all up now
|
||||
for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) {
|
||||
// fill the indices array
|
||||
int voxelIndexOffset = n * INDICES_PER_VOXEL;
|
||||
GLuint *currentIndicesPos = indicesArray + voxelIndexOffset;
|
||||
GLuint* currentIndicesPos = indicesArray + voxelIndexOffset;
|
||||
int startIndex = (n * VERTICES_PER_VOXEL);
|
||||
|
||||
for (int i = 0; i < INDICES_PER_VOXEL; i++) {
|
||||
|
@ -252,8 +256,8 @@ void VoxelSystem::init() {
|
|||
}
|
||||
}
|
||||
|
||||
GLfloat *normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
GLfloat *normalsArrayEndPointer = normalsArray;
|
||||
GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM];
|
||||
GLfloat* normalsArrayEndPointer = normalsArray;
|
||||
|
||||
// populate the normalsArray
|
||||
for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) {
|
||||
|
@ -263,25 +267,25 @@ void VoxelSystem::init() {
|
|||
}
|
||||
|
||||
// VBO for the verticesArray
|
||||
glGenBuffers(1, &vboVerticesID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glGenBuffers(1, &_vboVerticesID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
// VBO for the normalsArray
|
||||
glGenBuffers(1, &vboNormalsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
|
||||
glGenBuffers(1, &_vboNormalsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM,
|
||||
normalsArray, GL_STATIC_DRAW);
|
||||
|
||||
// VBO for colorsArray
|
||||
glGenBuffers(1, &vboColorsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
glGenBuffers(1, &_vboColorsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW);
|
||||
|
||||
// VBO for the indicesArray
|
||||
glGenBuffers(1, &vboIndicesID);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
|
||||
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);
|
||||
|
@ -291,45 +295,68 @@ void VoxelSystem::init() {
|
|||
delete[] normalsArray;
|
||||
}
|
||||
|
||||
void VoxelSystem::render() {
|
||||
void VoxelSystem::updateVBOs() {
|
||||
if (_voxelsDirty) {
|
||||
glBufferIndex segmentStart = 0;
|
||||
glBufferIndex segmentEnd = 0;
|
||||
|
||||
bool inSegment = false;
|
||||
for (glBufferIndex i = 0; i < _voxelsInArrays; i++) {
|
||||
if (!inSegment) {
|
||||
if (_voxelDirtyArray[i]) {
|
||||
segmentStart = i;
|
||||
inSegment = true;
|
||||
_voxelDirtyArray[i] = false; // consider us clean!
|
||||
}
|
||||
} else {
|
||||
if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) {
|
||||
segmentEnd = i;
|
||||
inSegment = false;
|
||||
int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||
|
||||
glPushMatrix();
|
||||
// vertices for segment - note: we might not need to do this
|
||||
GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
||||
GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);
|
||||
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||
|
||||
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) {
|
||||
// colors for segment
|
||||
segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);
|
||||
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLfloat), readVerticesArray);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLubyte), readColorsArray);
|
||||
|
||||
readVerticesEndPointer = readVerticesArray;
|
||||
|
||||
pthread_mutex_unlock(&bufferWriteLock);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
||||
}
|
||||
}
|
||||
}
|
||||
_voxelsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelSystem::render() {
|
||||
glPushMatrix();
|
||||
updateVBOs();
|
||||
// tell OpenGL where to find vertex and color information
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);
|
||||
glNormalPointer(GL_FLOAT, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vboColorsID);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||
|
||||
// draw the number of voxels we have
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
|
||||
glScalef(10, 10, 10);
|
||||
glDrawElements(GL_TRIANGLES, 36 * voxelsRendered, GL_UNSIGNED_INT, 0);
|
||||
glDrawElements(GL_TRIANGLES, 36 * _voxelsInArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
// deactivate vertex and color arrays after drawing
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
@ -350,12 +377,7 @@ void VoxelSystem::simulate(float deltaTime) {
|
|||
|
||||
int VoxelSystem::_nodeCount = 0;
|
||||
|
||||
bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
|
||||
// we do our operations on the way up!
|
||||
if (down) {
|
||||
return true;
|
||||
}
|
||||
bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {
|
||||
|
||||
_nodeCount++;
|
||||
if (node->isColored()) {
|
||||
|
@ -370,17 +392,12 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraDa
|
|||
|
||||
void VoxelSystem::randomizeVoxelColors() {
|
||||
_nodeCount = 0;
|
||||
tree->recurseTreeWithOperation(randomColorOperation);
|
||||
_tree->recurseTreeWithOperation(randomColorOperation);
|
||||
printLog("setting randomized true color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
|
||||
// we do our operations on the way up!
|
||||
if (down) {
|
||||
return true;
|
||||
}
|
||||
bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData) {
|
||||
|
||||
_nodeCount++;
|
||||
|
||||
|
@ -395,18 +412,12 @@ bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void*
|
|||
|
||||
void VoxelSystem::falseColorizeRandom() {
|
||||
_nodeCount = 0;
|
||||
tree->recurseTreeWithOperation(falseColorizeRandomOperation);
|
||||
_tree->recurseTreeWithOperation(falseColorizeRandomOperation);
|
||||
printLog("setting randomized false color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
|
||||
// we do our operations on the way up!
|
||||
if (down) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoxelSystem::trueColorizeOperation(VoxelNode* node, void* extraData) {
|
||||
_nodeCount++;
|
||||
node->setFalseColored(false);
|
||||
return true;
|
||||
|
@ -414,19 +425,13 @@ bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraD
|
|||
|
||||
void VoxelSystem::trueColorize() {
|
||||
_nodeCount = 0;
|
||||
tree->recurseTreeWithOperation(trueColorizeOperation);
|
||||
_tree->recurseTreeWithOperation(trueColorizeOperation);
|
||||
printLog("setting true color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
// Will false colorize voxels that are not in view
|
||||
bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
|
||||
// we do our operations on the way up!
|
||||
if (down) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, void* extraData) {
|
||||
const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData;
|
||||
|
||||
_nodeCount++;
|
||||
|
@ -448,25 +453,17 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void*
|
|||
|
||||
void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) {
|
||||
_nodeCount = 0;
|
||||
tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
|
||||
_tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);
|
||||
printLog("setting in view false color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
// Will false colorize voxels based on distance from view
|
||||
bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
|
||||
// we do our operations on the way up!
|
||||
if (down) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData) {
|
||||
ViewFrustum* viewFrustum = (ViewFrustum*) extraData;
|
||||
|
||||
// only do this for truly colored voxels...
|
||||
if (node->isColored()) {
|
||||
|
||||
// We need our distance for both up and down
|
||||
glm::vec3 nodePosition;
|
||||
float* startVertex = firstVertexForCode(node->octalCode);
|
||||
nodePosition.x = startVertex[0];
|
||||
|
@ -508,13 +505,7 @@ float VoxelSystem::_minDistance = FLT_MAX;
|
|||
// Helper function will get the distance from view range, would be nice if you could just keep track
|
||||
// of this as voxels are created and/or colored... seems like some transform math could do that so
|
||||
// we wouldn't need to do two passes of the tree
|
||||
bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
|
||||
// we do our operations on the way up!
|
||||
if (down) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData) {
|
||||
ViewFrustum* viewFrustum = (ViewFrustum*) extraData;
|
||||
|
||||
// only do this for truly colored voxels...
|
||||
|
@ -538,7 +529,7 @@ bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down,
|
|||
powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) +
|
||||
powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2));
|
||||
|
||||
// on way down, calculate the range of distances
|
||||
// calculate the range of distances
|
||||
if (distance > _maxDistance) {
|
||||
_maxDistance = distance;
|
||||
}
|
||||
|
@ -556,12 +547,14 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) {
|
|||
|
||||
_maxDistance = 0.0;
|
||||
_minDistance = FLT_MAX;
|
||||
tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);
|
||||
_tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);
|
||||
printLog("determining distance range for %d nodes\n",_nodeCount);
|
||||
|
||||
_nodeCount = 0;
|
||||
|
||||
tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
|
||||
_tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);
|
||||
printLog("setting in distance false color for %d nodes\n",_nodeCount);
|
||||
setupNewVoxelsForDrawing();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,12 +29,16 @@ public:
|
|||
|
||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||
VoxelSystem* clone() const;
|
||||
|
||||
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; };
|
||||
|
||||
void init();
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
void setVoxelsRendered(int v) {voxelsRendered = v;};
|
||||
int getVoxelsRendered() {return voxelsRendered;};
|
||||
|
||||
unsigned long getVoxelsUpdated() const {return _voxelsUpdated;};
|
||||
unsigned long getVoxelsRendered() const {return _voxelsInArrays;};
|
||||
|
||||
void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; };
|
||||
void setCamera(Camera* newCamera) { _camera = newCamera; };
|
||||
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
|
||||
|
@ -57,36 +61,42 @@ public:
|
|||
private:
|
||||
// Operation functions for tree recursion methods
|
||||
static int _nodeCount;
|
||||
static bool randomColorOperation(VoxelNode* node, bool down, void* extraData);
|
||||
static bool falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData);
|
||||
static bool trueColorizeOperation(VoxelNode* node, bool down, void* extraData);
|
||||
static bool falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData);
|
||||
static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData);
|
||||
static bool getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData);
|
||||
static bool randomColorOperation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeRandomOperation(VoxelNode* node, void* extraData);
|
||||
static bool trueColorizeOperation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeInViewOperation(VoxelNode* node, void* extraData);
|
||||
static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData);
|
||||
static bool getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData);
|
||||
|
||||
// these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here
|
||||
static float _maxDistance;
|
||||
static float _minDistance;
|
||||
|
||||
int voxelsRendered;
|
||||
Avatar* _viewerAvatar;
|
||||
Camera* _camera;
|
||||
VoxelTree *tree;
|
||||
GLfloat *readVerticesArray;
|
||||
GLubyte *readColorsArray;
|
||||
GLfloat *readVerticesEndPointer;
|
||||
GLfloat *writeVerticesArray;
|
||||
GLubyte *writeColorsArray;
|
||||
GLfloat *writeVerticesEndPointer;
|
||||
GLuint vboVerticesID;
|
||||
GLuint vboNormalsID;
|
||||
GLuint vboColorsID;
|
||||
GLuint vboIndicesID;
|
||||
pthread_mutex_t bufferWriteLock;
|
||||
VoxelTree* _tree;
|
||||
GLfloat* _readVerticesArray;
|
||||
GLubyte* _readColorsArray;
|
||||
GLfloat* _writeVerticesArray;
|
||||
GLubyte* _writeColorsArray;
|
||||
bool* _voxelDirtyArray;
|
||||
unsigned long _voxelsUpdated;
|
||||
unsigned long _voxelsInArrays;
|
||||
|
||||
GLuint _vboVerticesID;
|
||||
GLuint _vboNormalsID;
|
||||
GLuint _vboColorsID;
|
||||
GLuint _vboIndicesID;
|
||||
pthread_mutex_t _bufferWriteLock;
|
||||
|
||||
int treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosition);
|
||||
ViewFrustum* _viewFrustum;
|
||||
|
||||
int newTreeToArrays(VoxelNode *currentNode);
|
||||
void setupNewVoxelsForDrawing();
|
||||
void copyWrittenDataToReadArrays();
|
||||
void updateVBOs();
|
||||
|
||||
bool _voxelsDirty;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -230,7 +230,7 @@ void displayStats(void)
|
|||
drawtext(10, statsVerticalOffset + 49, 0.10f, 0, 1.0, 0, stats);
|
||||
|
||||
std::stringstream voxelStats;
|
||||
voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered();
|
||||
voxelStats << "Voxels Rendered: " << voxels.getVoxelsRendered() << " Updated: " << voxels.getVoxelsUpdated();
|
||||
drawtext(10, statsVerticalOffset + 70, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||
|
||||
voxelStats.str("");
|
||||
|
@ -1612,6 +1612,8 @@ void audioMixerUpdate(in_addr_t newMixerAddress, in_port_t newMixerPort) {
|
|||
|
||||
int main(int argc, const char * argv[])
|
||||
{
|
||||
voxels.setViewFrustum(&::viewFrustum);
|
||||
|
||||
shared_lib::printLog = & ::printLog;
|
||||
voxels_lib::printLog = & ::printLog;
|
||||
avatars_lib::printLog = & ::printLog;
|
||||
|
@ -1634,7 +1636,7 @@ int main(int argc, const char * argv[])
|
|||
}
|
||||
|
||||
// Handle Local Domain testing with the --local command line
|
||||
if (cmdOptionExists(argc, argv, "--local")) {
|
||||
if (true || cmdOptionExists(argc, argv, "--local")) {
|
||||
printLog("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));
|
||||
|
|
|
@ -21,4 +21,7 @@ const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
|||
const int INDICES_PER_VOXEL = 3 * 12;
|
||||
const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
|
||||
|
||||
typedef unsigned long int glBufferIndex;
|
||||
const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,10 @@ VoxelNode::VoxelNode() {
|
|||
for (int i = 0; i < 8; i++) {
|
||||
children[i] = NULL;
|
||||
}
|
||||
|
||||
_glBufferIndex = GLBUFFER_INDEX_UNKNOWN;
|
||||
_isDirty = true;
|
||||
_shouldRender = false;
|
||||
}
|
||||
|
||||
VoxelNode::~VoxelNode() {
|
||||
|
@ -43,6 +47,14 @@ VoxelNode::~VoxelNode() {
|
|||
}
|
||||
}
|
||||
|
||||
void VoxelNode::setShouldRender(bool shouldRender) {
|
||||
// if shouldRender is changing, then consider ourselves dirty
|
||||
if (shouldRender != _shouldRender) {
|
||||
_shouldRender = shouldRender;
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelNode::getAABox(AABox& box) const {
|
||||
|
||||
glm::vec3 corner;
|
||||
|
@ -59,16 +71,19 @@ void VoxelNode::getAABox(AABox& box) const {
|
|||
}
|
||||
|
||||
void VoxelNode::addChildAtIndex(int childIndex) {
|
||||
children[childIndex] = new VoxelNode();
|
||||
if (!children[childIndex]) {
|
||||
children[childIndex] = new VoxelNode();
|
||||
|
||||
// XXXBHG - When the node is constructed, it should be cleanly set up as
|
||||
// true colored, but for some reason, not so much. I've added a a basecamp
|
||||
// to-do to research this. But for now we'll use belt and suspenders and set
|
||||
// it to not-false-colored here!
|
||||
children[childIndex]->setFalseColored(false);
|
||||
// XXXBHG - When the node is constructed, it should be cleanly set up as
|
||||
// true colored, but for some reason, not so much. I've added a a basecamp
|
||||
// to-do to research this. But for now we'll use belt and suspenders and set
|
||||
// it to not-false-colored here!
|
||||
children[childIndex]->setFalseColored(false);
|
||||
|
||||
// give this child its octal code
|
||||
children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
|
||||
// give this child its octal code
|
||||
children[childIndex]->octalCode = childOctalCode(octalCode, childIndex);
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
// will average the child colors...
|
||||
|
@ -104,26 +119,35 @@ void VoxelNode::setColorFromAverageOfChildren() {
|
|||
// the actual NO_FALSE_COLOR version are inline in the VoxelNode.h
|
||||
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
||||
void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) {
|
||||
_falseColored=true;
|
||||
_currentColor[0] = red;
|
||||
_currentColor[1] = green;
|
||||
_currentColor[2] = blue;
|
||||
_currentColor[3] = 1; // XXXBHG - False colors are always considered set
|
||||
if (_falseColored != true || _currentColor[0] != red || _currentColor[1] != green || _currentColor[2] != blue) {
|
||||
_falseColored=true;
|
||||
_currentColor[0] = red;
|
||||
_currentColor[1] = green;
|
||||
_currentColor[2] = blue;
|
||||
_currentColor[3] = 1; // XXXBHG - False colors are always considered set
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelNode::setFalseColored(bool isFalseColored) {
|
||||
// if we were false colored, and are no longer false colored, then swap back
|
||||
if (_falseColored && !isFalseColored) {
|
||||
memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
|
||||
if (_falseColored != isFalseColored) {
|
||||
// if we were false colored, and are no longer false colored, then swap back
|
||||
if (_falseColored && !isFalseColored) {
|
||||
memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
|
||||
}
|
||||
_falseColored = isFalseColored;
|
||||
_isDirty = true;
|
||||
}
|
||||
_falseColored = isFalseColored;
|
||||
};
|
||||
|
||||
|
||||
void VoxelNode::setColor(const nodeColor& color) {
|
||||
memcpy(&_trueColor,&color,sizeof(nodeColor));
|
||||
if (!_falseColored) {
|
||||
memcpy(&_currentColor,&color,sizeof(nodeColor));
|
||||
if (_trueColor[0] != color[0] || _trueColor[1] != color[1] || _trueColor[2] != color[2]) {
|
||||
memcpy(&_trueColor,&color,sizeof(nodeColor));
|
||||
if (!_falseColored) {
|
||||
memcpy(&_currentColor,&color,sizeof(nodeColor));
|
||||
}
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -199,7 +223,6 @@ void VoxelNode::printDebugDetails(const char* label) const {
|
|||
printOctalCode(octalCode);
|
||||
}
|
||||
|
||||
|
||||
bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const {
|
||||
AABox box;
|
||||
getAABox(box);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "AABox.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "VoxelConstants.h"
|
||||
|
||||
typedef unsigned char colorPart;
|
||||
typedef unsigned char nodeColor[4];
|
||||
|
@ -22,6 +23,11 @@ private:
|
|||
nodeColor _currentColor;
|
||||
bool _falseColored;
|
||||
#endif
|
||||
|
||||
glBufferIndex _glBufferIndex;
|
||||
bool _isDirty;
|
||||
bool _shouldRender;
|
||||
|
||||
public:
|
||||
VoxelNode();
|
||||
~VoxelNode();
|
||||
|
@ -40,6 +46,18 @@ public:
|
|||
bool isLeaf() const;
|
||||
void getAABox(AABox& box) const;
|
||||
void printDebugDetails(const char* label) const;
|
||||
|
||||
bool isDirty() const { return _isDirty; };
|
||||
void clearDirtyBit() { _isDirty = false; };
|
||||
|
||||
glBufferIndex getBufferIndex() const { return _glBufferIndex; };
|
||||
bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); };
|
||||
void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; };
|
||||
|
||||
// whether or not we should render
|
||||
void setShouldRender(bool shouldRender);
|
||||
bool getShouldRender() const { return _shouldRender; }
|
||||
|
||||
|
||||
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
||||
void setFalseColor(colorPart red, colorPart green, colorPart blue);
|
||||
|
|
|
@ -58,16 +58,13 @@ void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, vo
|
|||
|
||||
// Recurses voxel node with an operation function
|
||||
void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData) {
|
||||
// call the operation function going "down" first, stop deeper recursion if function returns false
|
||||
if (operation(node,true,extraData)) {
|
||||
for (int i = 0; i < sizeof(node->children)/sizeof(node->children[0]); i++) {
|
||||
if (operation(node, extraData)) {
|
||||
for (int i = 0; i < sizeof(node->children) / sizeof(node->children[0]); i++) {
|
||||
VoxelNode* child = node->children[i];
|
||||
if (child) {
|
||||
recurseNodeWithOperation(child,operation,extraData);
|
||||
recurseNodeWithOperation(child, operation, extraData);
|
||||
}
|
||||
}
|
||||
// call operation on way back up
|
||||
operation(node,false,extraData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "VoxelNodeBag.h"
|
||||
|
||||
// Callback function, for recuseTreeWithOperation
|
||||
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData);
|
||||
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData);
|
||||
|
||||
class VoxelTree {
|
||||
public:
|
||||
|
|
|
@ -38,7 +38,7 @@ const float DEATH_STAR_RADIUS = 4.0;
|
|||
const float MAX_CUBE = 0.05f;
|
||||
|
||||
const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000;
|
||||
const int PACKETS_PER_CLIENT_PER_INTERVAL = 2;
|
||||
const int PACKETS_PER_CLIENT_PER_INTERVAL = 20;
|
||||
|
||||
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
|
||||
|
||||
|
@ -68,11 +68,9 @@ void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) {
|
|||
}
|
||||
|
||||
int _nodeCount=0;
|
||||
bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) {
|
||||
if (down) {
|
||||
if (node->isColored()){
|
||||
_nodeCount++;
|
||||
}
|
||||
bool countVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||
if (node->isColored()){
|
||||
_nodeCount++;
|
||||
}
|
||||
return true; // keep going
|
||||
}
|
||||
|
@ -80,7 +78,7 @@ bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) {
|
|||
void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) {
|
||||
printf("adding scene of spheres...\n");
|
||||
|
||||
int sphereBaseSize = 256;
|
||||
int sphereBaseSize = 512;
|
||||
|
||||
tree->createSphere(0.25, 0.5, 0.5, 0.5, (1.0 / sphereBaseSize), true, wantColorRandomizer);
|
||||
printf("one sphere added...\n");
|
||||
|
|
Loading…
Reference in a new issue