Showing the changes to interface/src/VoxelSystem.cpp (1 of 10 files). Show all
Unified · Split
| @@ -41,69 +41,53 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- . · 40 unmodified lines | |||
| 41 | 4,5,6, 4,6,7 }; // Z+ . | 41 | 4,5,6, 4,6,7 }; // Z+ . |
| 42 | 42 | ||
| 43 | VoxelSystem::VoxelSystem() { | 43 | VoxelSystem::VoxelSystem() { |
| 44 | voxelsRendered = 0; | 44 | _voxelsInArrays = _voxelsUpdated = 0; |
| 45 | tree = new VoxelTree(); | 45 | _tree = new VoxelTree(); |
| 46 | pthread_mutex_init(&bufferWriteLock, NULL); | 46 | pthread_mutex_init(&_bufferWriteLock, NULL); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | VoxelSystem::~VoxelSystem() { | 49 | VoxelSystem::~VoxelSystem() { |
| 50 | delete[] readVerticesArray; | 50 | delete[] _readVerticesArray; |
| 51 | delete[] writeVerticesArray; | 51 | delete[] _writeVerticesArray; |
| 52 | delete[] readColorsArray; | 52 | delete[] _readColorsArray; |
| 53 | delete[] writeColorsArray; | 53 | delete[] _writeColorsArray; |
| 54 | delete tree; | 54 | delete[] _voxelDirtyArray; |
| 55 | pthread_mutex_destroy(&bufferWriteLock); | 55 | delete _tree; |
| 56 | pthread_mutex_destroy(&_bufferWriteLock); | ||
| 56 | } | 57 | } |
| 57 | 58 | ||
| 58 | ////////////////////////////////////////////////////////////////////////////////////////// | ||
| 59 | // Method: VoxelSystem::loadVoxelsFile() | ||
| 60 | // Description: Loads HiFidelity encoded Voxels from a binary file. The current file | ||
| 61 | // format is a stream of single voxels with NO color data. Currently | ||
| 62 | // colors are set randomly | ||
| 63 | // Complaints: Brad :) | ||
| 64 | // To Do: Need to add color data to the file. | ||
| 65 | void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { | 59 | void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { |
| 66 | 60 | _tree->loadVoxelsFile(fileName, wantColorRandomizer); | |
| 67 | tree->loadVoxelsFile(fileName,wantColorRandomizer); | ||
| 68 | |||
| 69 | copyWrittenDataToReadArrays(); | 61 | copyWrittenDataToReadArrays(); |
| 70 | } | 62 | } |
| 71 | 63 | ||
| 72 | ////////////////////////////////////////////////////////////////////////////////////////// | ||
| 73 | // Method: VoxelSystem::createSphere() | ||
| 74 | // Description: Creates a sphere of voxels in the local system at a given location/radius | ||
| 75 | // To Do: Move this function someplace better? I put it here because we need a | ||
| 76 | // mechanism to tell the system to redraw it's arrays after voxels are done | ||
| 77 | // being added. This is a concept mostly only understood by VoxelSystem. | ||
| 78 | // Complaints: Brad :) | ||
| 79 | void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) { | 64 | void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) { |
| 80 | 65 | _tree->createSphere(r, xc, yc, zc, s, solid, wantColorRandomizer); | |
| 81 | tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer); | ||
| 82 | setupNewVoxelsForDrawing(); | 66 | setupNewVoxelsForDrawing(); |
| 83 | } | 67 | } |
| 84 | 68 | ||
| 85 | long int VoxelSystem::getVoxelsCreated() { | 69 | long int VoxelSystem::getVoxelsCreated() { |
| 86 | return tree->voxelsCreated; | 70 | return _tree->voxelsCreated; |
| 87 | } | 71 | } |
| 88 | 72 | ||
| 89 | float VoxelSystem::getVoxelsCreatedPerSecondAverage() { | 73 | float VoxelSystem::getVoxelsCreatedPerSecondAverage() { |
| 90 | return (1 / tree->voxelsCreatedStats.getEventDeltaAverage()); | 74 | return (1 / _tree->voxelsCreatedStats.getEventDeltaAverage()); |
| 91 | } | 75 | } |
| 92 | 76 | ||
| 93 | long int VoxelSystem::getVoxelsColored() { | 77 | long int VoxelSystem::getVoxelsColored() { |
| 94 | return tree->voxelsColored; | 78 | return _tree->voxelsColored; |
| 95 | } | 79 | } |
| 96 | 80 | ||
| 97 | float VoxelSystem::getVoxelsColoredPerSecondAverage() { | 81 | float VoxelSystem::getVoxelsColoredPerSecondAverage() { |
| 98 | return (1 / tree->voxelsColoredStats.getEventDeltaAverage()); | 82 | return (1 / _tree->voxelsColoredStats.getEventDeltaAverage()); |
| 99 | } | 83 | } |
| 100 | 84 | ||
| 101 | long int VoxelSystem::getVoxelsBytesRead() { | 85 | long int VoxelSystem::getVoxelsBytesRead() { |
| 102 | return tree->voxelsBytesRead; | 86 | return _tree->voxelsBytesRead; |
| 103 | } | 87 | } |
| 104 | 88 | ||
| 105 | float VoxelSystem::getVoxelsBytesReadPerSecondAverage() { | 89 | float VoxelSystem::getVoxelsBytesReadPerSecondAverage() { |
| 106 | return tree->voxelsBytesReadStats.getAverageSampleValuePerSecond(); | 90 | return _tree->voxelsBytesReadStats.getAverageSampleValuePerSecond(); |
| 107 | } | 91 | } |
| 108 | 92 | ||
| 109 | int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { | 93 | int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { |
| @@ -114,11 +98,11 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 4 unmodified lines | |||
| 114 | switch(command) { | 98 | switch(command) { |
| 115 | case PACKET_HEADER_VOXEL_DATA: | 99 | case PACKET_HEADER_VOXEL_DATA: |
| 116 | // ask the VoxelTree to read the bitstream into the tree | 100 | // ask the VoxelTree to read the bitstream into the tree |
| 117 | tree->readBitstreamToTree(voxelData, numBytes - 1); | 101 | _tree->readBitstreamToTree(voxelData, numBytes - 1); |
| 118 | break; | 102 | break; |
| 119 | case PACKET_HEADER_ERASE_VOXEL: | 103 | case PACKET_HEADER_ERASE_VOXEL: |
| 120 | // ask the tree to read the "remove" bitstream | 104 | // ask the tree to read the "remove" bitstream |
| 121 | tree->processRemoveVoxelBitstream(sourceBuffer, numBytes); | 105 | _tree->processRemoveVoxelBitstream(sourceBuffer, numBytes); |
| 122 | break; | 106 | break; |
| 123 | case PACKET_HEADER_Z_COMMAND: | 107 | case PACKET_HEADER_Z_COMMAND: |
| 124 | 108 | ||
| @@ -135,7 +119,8 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 10 unmodified lines | |||
| 135 | while (totalLength <= numBytes) { | 119 | while (totalLength <= numBytes) { |
| 136 | if (0==strcmp(command,(char*)"erase all")) { | 120 | if (0==strcmp(command,(char*)"erase all")) { |
| 137 | printLog("got Z message == erase all\n"); | 121 | printLog("got Z message == erase all\n"); |
| 138 | tree->eraseAllVoxels(); | 122 | _tree->eraseAllVoxels(); |
| 123 | _voxelsInArrays = 0; // better way to do this?? | ||
| 139 | } | 124 | } |
| 140 | if (0==strcmp(command,(char*)"add scene")) { | 125 | if (0==strcmp(command,(char*)"add scene")) { |
| 141 | printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); | 126 | printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); |
| @@ -150,78 +135,87 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 8 unmodified lines | |||
| 150 | } | 135 | } |
| 151 | 136 | ||
| 152 | void VoxelSystem::setupNewVoxelsForDrawing() { | 137 | void VoxelSystem::setupNewVoxelsForDrawing() { |
| 153 | // reset the verticesEndPointer so we're writing to the beginning of the array | 138 | _voxelsUpdated = newTreeToArrays(_tree->rootNode); |
| 154 | writeVerticesEndPointer = writeVerticesArray; | 139 | if (_voxelsUpdated) { |
| 155 | // call recursive function to populate in memory arrays | 140 | _voxelsDirty=true; |
| 156 | // it will return the number of voxels added | 141 | } |
| 157 | glm::vec3 treeRoot = glm::vec3(0,0,0); | 142 | |
| 158 | voxelsRendered = treeToArrays(tree->rootNode, treeRoot); | ||
| 159 | // copy the newly written data to the arrays designated for reading | 143 | // copy the newly written data to the arrays designated for reading |
| 160 | copyWrittenDataToReadArrays(); | 144 | copyWrittenDataToReadArrays(); |
| 161 | } | 145 | } |
| 162 | 146 | ||
| 163 | void VoxelSystem::copyWrittenDataToReadArrays() { | 147 | void VoxelSystem::copyWrittenDataToReadArrays() { |
| 164 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it | 148 | if (_voxelsDirty) { |
| 165 | pthread_mutex_lock(&bufferWriteLock); | 149 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it |
| 166 | // store a pointer to the current end so it doesn't change during copy | 150 | pthread_mutex_lock(&_bufferWriteLock); |
| 167 | GLfloat *endOfCurrentVerticesData = writeVerticesEndPointer; | 151 | int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); |
| 168 | // copy the vertices and colors | 152 | int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); |
| 169 | memcpy(readVerticesArray, writeVerticesArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLfloat)); | 153 | memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices); |
| 170 | memcpy(readColorsArray, writeColorsArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLubyte)); | 154 | memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); |
| 171 | // set the read vertices end pointer to the correct spot so the GPU knows how much to pull | 155 | pthread_mutex_unlock(&_bufferWriteLock); |
| 172 | readVerticesEndPointer = readVerticesArray + (endOfCurrentVerticesData - writeVerticesArray); | 156 | } |
| 173 | pthread_mutex_unlock(&bufferWriteLock); | ||
| 174 | } | 157 | } |
| 175 | 158 | ||
| 176 | int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosition) { | 159 | int VoxelSystem::newTreeToArrays(VoxelNode* node) { |
| 177 | int voxelsAdded = 0; | 160 | assert(_viewFrustum); // you must set up _viewFrustum before calling this |
| 178 | float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE); | 161 | int voxelsUpdated = 0; |
| 179 | glm::vec3 viewerPosition = _camera->getPosition(); //_viewerAvatar->getPosition(); | 162 | float distanceToNode = node->distanceToCamera(*_viewFrustum); |
| 180 | 163 | float boundary = boundaryDistanceForRenderLevel(*node->octalCode + 1); | |
| 181 | // debug LOD code | 164 | float childBoundary = boundaryDistanceForRenderLevel(*node->octalCode + 2); |
| 182 | glm::vec3 debugNodePosition; | 165 | bool inBoundary = (distanceToNode <= boundary); |
| 183 | copyFirstVertexForCode(currentNode->octalCode,(float*)&debugNodePosition); | 166 | bool inChildBoundary = (distanceToNode <= childBoundary); |
| 184 | 167 | bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary)); | |
| 185 | float distanceToVoxelCenter = sqrtf(powf(viewerPosition.x - nodePosition[0] - halfUnitForVoxel, 2) + | 168 | |
| 186 | powf(viewerPosition.y - nodePosition[1] - halfUnitForVoxel, 2) + | 169 | node->setShouldRender(shouldRender); |
| 187 | powf(viewerPosition.z - nodePosition[2] - halfUnitForVoxel, 2)); | 170 | // let children figure out their renderness |
| 188 | 171 | for (int i = 0; i < 8; i++) { | |
| 189 | int renderLevel = *currentNode->octalCode + 1; | 172 | if (node->children[i]) { |
| 190 | int boundaryPosition = boundaryDistanceForRenderLevel(renderLevel); | 173 | voxelsUpdated += newTreeToArrays(node->children[i]); |
| 191 | bool alwaysDraw = false; // XXXBHG - temporary debug code. Flip this to true to disable LOD blurring | ||
| 192 | |||
| 193 | if (alwaysDraw || distanceToVoxelCenter < boundaryPosition) { | ||
| 194 | for (int i = 0; i < 8; i++) { | ||
| 195 | // check if there is a child here | ||
| 196 | if (currentNode->children[i] != NULL) { | ||
| 197 | |||
| 198 | glm::vec3 childNodePosition; | ||
| 199 | copyFirstVertexForCode(currentNode->children[i]->octalCode,(float*)&childNodePosition); | ||
| 200 | childNodePosition *= (float)TREE_SCALE; // scale it up | ||
| 201 | voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition); | ||
| 202 | } | ||
| 203 | } | 174 | } |
| 204 | } | 175 | } |
| 176 | |||
| 177 | // Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us | ||
| 178 | if (node->isDirty() && (shouldRender || node->isKnownBufferIndex())) { | ||
| 179 | glm::vec3 startVertex; | ||
| 180 | float voxelScale = 0; | ||
| 181 | |||
| 182 | // If we're should render, use our legit location and scale, | ||
| 183 | if (node->getShouldRender()) { | ||
| 184 | copyFirstVertexForCode(node->octalCode, (float*)&startVertex); | ||
| 185 | voxelScale = (1 / powf(2, *node->octalCode)); | ||
| 186 | } else { | ||
| 187 | // if we shouldn't render then set out location to some infinitely distant location, | ||
| 188 | // and our scale as infinitely small | ||
| 189 | startVertex[0] = startVertex[1] = startVertex[2] = FLT_MAX; | ||
| 190 | voxelScale = 0; | ||
| 191 | } | ||
| 205 | 192 | ||
| 206 | // if we didn't get any voxels added then we're a leaf | 193 | // If this node has not yet been written to the array, then add it to the end of the array. |
| 207 | // add our vertex and color information to the interleaved array | 194 | glBufferIndex nodeIndex; |
| 208 | if (voxelsAdded == 0 && currentNode->isColored()) { | 195 | if (node->isKnownBufferIndex()) { |
| 209 | float startVertex[3]; | 196 | nodeIndex = node->getBufferIndex(); |
| 210 | copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex); | 197 | } else { |
| 211 | float voxelScale = 1 / powf(2, *currentNode->octalCode); | 198 | nodeIndex = _voxelsInArrays; |
| 199 | } | ||
| 200 | |||
| 201 | _voxelDirtyArray[nodeIndex] = true; | ||
| 212 | 202 | ||
| 213 | // populate the array with points for the 8 vertices | 203 | // populate the array with points for the 8 vertices |
| 214 | // and RGB color for each added vertex | 204 | // and RGB color for each added vertex |
| 215 | for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { | 205 | for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { |
| 216 | *writeVerticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale); | 206 | GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); |
| 217 | *(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->getColor()[j % 3]; | 207 | GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); |
| 218 | 208 | *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); | |
| 219 | writeVerticesEndPointer++; | 209 | *(writeColorsAt +j) = node->getColor()[j % 3]; |
| 210 | } | ||
| 211 | if (!node->isKnownBufferIndex()) { | ||
| 212 | node->setBufferIndex(nodeIndex); | ||
| 213 | _voxelsInArrays++; // our know vertices in the arrays | ||
| 220 | } | 214 | } |
| 221 | voxelsAdded++; | 215 | voxelsUpdated++; |
| 216 | node->clearDirtyBit(); | ||
| 222 | } | 217 | } |
| 223 | 218 | return voxelsUpdated; | |
| 224 | return voxelsAdded; | ||
| 225 | } | 219 | } |
| 226 | 220 | ||
| 227 | VoxelSystem* VoxelSystem::clone() const { | 221 | VoxelSystem* VoxelSystem::clone() const { |
| @@ -230,20 +224,30 @@ VoxelSystem* VoxelSystem::clone() const { · 2 unmodified lines | |||
| 230 | } | 224 | } |
| 231 | 225 | ||
| 232 | void VoxelSystem::init() { | 226 | void VoxelSystem::init() { |
| 227 | |||
| 228 | // When we change voxels representations in the arrays, we'll update this | ||
| 229 | _voxelsDirty = false; | ||
| 230 | _voxelsInArrays = 0; | ||
| 231 | |||
| 232 | // we will track individual dirty sections with this array of bools | ||
| 233 | _voxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; | ||
| 234 | memset(_voxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool)); | ||
| 235 | |||
| 233 | // prep the data structures for incoming voxel data | 236 | // prep the data structures for incoming voxel data |
| 234 | writeVerticesEndPointer = writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; | 237 | _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; |
| 235 | readVerticesEndPointer = readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; | 238 | _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; |
| 236 | writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; | 239 | |
| 237 | readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; | 240 | _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; |
| 241 | _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; | ||
| 238 | 242 | ||
| 239 | GLuint *indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; | 243 | GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; |
| 240 | 244 | ||
| 241 | // populate the indicesArray | 245 | // populate the indicesArray |
| 242 | // this will not change given new voxels, so we can set it all up now | 246 | // this will not change given new voxels, so we can set it all up now |
| 243 | for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { | 247 | for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { |
| 244 | // fill the indices array | 248 | // fill the indices array |
| 245 | int voxelIndexOffset = n * INDICES_PER_VOXEL; | 249 | int voxelIndexOffset = n * INDICES_PER_VOXEL; |
| 246 | GLuint *currentIndicesPos = indicesArray + voxelIndexOffset; | 250 | GLuint* currentIndicesPos = indicesArray + voxelIndexOffset; |
| 247 | int startIndex = (n * VERTICES_PER_VOXEL); | 251 | int startIndex = (n * VERTICES_PER_VOXEL); |
| 248 | 252 | ||
| 249 | for (int i = 0; i < INDICES_PER_VOXEL; i++) { | 253 | for (int i = 0; i < INDICES_PER_VOXEL; i++) { |
| @@ -252,8 +256,8 @@ void VoxelSystem::init() { · 2 unmodified lines | |||
| 252 | } | 256 | } |
| 253 | } | 257 | } |
| 254 | 258 | ||
| 255 | GLfloat *normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; | 259 | GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; |
| 256 | GLfloat *normalsArrayEndPointer = normalsArray; | 260 | GLfloat* normalsArrayEndPointer = normalsArray; |
| 257 | 261 | ||
| 258 | // populate the normalsArray | 262 | // populate the normalsArray |
| 259 | for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { | 263 | for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { |
| @@ -263,25 +267,25 @@ void VoxelSystem::init() { · 3 unmodified lines | |||
| 263 | } | 267 | } |
| 264 | 268 | ||
| 265 | // VBO for the verticesArray | 269 | // VBO for the verticesArray |
| 266 | glGenBuffers(1, &vboVerticesID); | 270 | glGenBuffers(1, &_vboVerticesID); |
| 267 | glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID); | 271 | glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); |
| 268 | glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); | 272 | glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); |
| 269 | 273 | ||
| 270 | // VBO for the normalsArray | 274 | // VBO for the normalsArray |
| 271 | glGenBuffers(1, &vboNormalsID); | 275 | glGenBuffers(1, &_vboNormalsID); |
| 272 | glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID); | 276 | glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); |
| 273 | glBufferData(GL_ARRAY_BUFFER, | 277 | glBufferData(GL_ARRAY_BUFFER, |
| 274 | VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, | 278 | VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, |
| 275 | normalsArray, GL_STATIC_DRAW); | 279 | normalsArray, GL_STATIC_DRAW); |
| 276 | 280 | ||
| 277 | // VBO for colorsArray | 281 | // VBO for colorsArray |
| 278 | glGenBuffers(1, &vboColorsID); | 282 | glGenBuffers(1, &_vboColorsID); |
| 279 | glBindBuffer(GL_ARRAY_BUFFER, vboColorsID); | 283 | glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); |
| 280 | glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); | 284 | glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); |
| 281 | 285 | ||
| 282 | // VBO for the indicesArray | 286 | // VBO for the indicesArray |
| 283 | glGenBuffers(1, &vboIndicesID); | 287 | glGenBuffers(1, &_vboIndicesID); |
| 284 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID); | 288 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); |
| 285 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, | 289 | glBufferData(GL_ELEMENT_ARRAY_BUFFER, |
| 286 | INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM, | 290 | INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM, |
| 287 | indicesArray, GL_STATIC_DRAW); | 291 | indicesArray, GL_STATIC_DRAW); |
| @@ -291,45 +295,68 @@ void VoxelSystem::init() { · 3 unmodified lines | |||
| 291 | delete[] normalsArray; | 295 | delete[] normalsArray; |
| 292 | } | 296 | } |
| 293 | 297 | ||
| 294 | void VoxelSystem::render() { | 298 | void VoxelSystem::updateVBOs() { |
| 295 | 299 | if (_voxelsDirty) { | |
| 296 | glPushMatrix(); | 300 | glBufferIndex segmentStart = 0; |
| 297 | 301 | glBufferIndex segmentEnd = 0; | |
| 298 | if (readVerticesEndPointer != readVerticesArray) { | 302 | |
| 299 | // try to lock on the buffer write | 303 | bool inSegment = false; |
| 300 | // just avoid pulling new data if it is currently being written | 304 | for (glBufferIndex i = 0; i < _voxelsInArrays; i++) { |
| 301 | if (pthread_mutex_trylock(&bufferWriteLock) == 0) { | 305 | if (!inSegment) { |
| 302 | 306 | if (_voxelDirtyArray[i]) { | |
| 303 | glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID); | 307 | segmentStart = i; |
| 304 | glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLfloat), readVerticesArray); | 308 | inSegment = true; |
| 305 | 309 | _voxelDirtyArray[i] = false; // consider us clean! | |
| 306 | glBindBuffer(GL_ARRAY_BUFFER, vboColorsID); | 310 | } |
| 307 | glBufferSubData(GL_ARRAY_BUFFER, 0, (readVerticesEndPointer - readVerticesArray) * sizeof(GLubyte), readColorsArray); | 311 | } else { |
| 308 | 312 | if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) { | |
| 309 | readVerticesEndPointer = readVerticesArray; | 313 | segmentEnd = i; |
| 310 | 314 | inSegment = false; | |
| 311 | pthread_mutex_unlock(&bufferWriteLock); | 315 | int segmentLength = (segmentEnd - segmentStart) + 1; |
| 316 | |||
| 317 | // vertices for segment - note: we might not need to do this | ||
| 318 | GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | ||
| 319 | GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | ||
| 320 | GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | ||
| 321 | |||
| 322 | glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); | ||
| 323 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); | ||
| 324 | |||
| 325 | // colors for segment | ||
| 326 | segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | ||
| 327 | segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | ||
| 328 | GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | ||
| 329 | |||
| 330 | glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); | ||
| 331 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); | ||
| 332 | } | ||
| 333 | } | ||
| 312 | } | 334 | } |
| 335 | _voxelsDirty = false; | ||
| 313 | } | 336 | } |
| 337 | } | ||
| 314 | 338 | ||
| 339 | void VoxelSystem::render() { | ||
| 340 | glPushMatrix(); | ||
| 341 | updateVBOs(); | ||
| 315 | // tell OpenGL where to find vertex and color information | 342 | // tell OpenGL where to find vertex and color information |
| 316 | glEnableClientState(GL_VERTEX_ARRAY); | 343 | glEnableClientState(GL_VERTEX_ARRAY); |
| 317 | glEnableClientState(GL_NORMAL_ARRAY); | 344 | glEnableClientState(GL_NORMAL_ARRAY); |
| 318 | glEnableClientState(GL_COLOR_ARRAY); | 345 | glEnableClientState(GL_COLOR_ARRAY); |
| 319 | 346 | ||
| 320 | glBindBuffer(GL_ARRAY_BUFFER, vboVerticesID); | 347 | glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); |
| 321 | glVertexPointer(3, GL_FLOAT, 0, 0); | 348 | glVertexPointer(3, GL_FLOAT, 0, 0); |
| 322 | 349 | ||
| 323 | glBindBuffer(GL_ARRAY_BUFFER, vboNormalsID); | 350 | glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); |
| 324 | glNormalPointer(GL_FLOAT, 0, 0); | 351 | glNormalPointer(GL_FLOAT, 0, 0); |
| 325 | 352 | ||
| 326 | glBindBuffer(GL_ARRAY_BUFFER, vboColorsID); | 353 | glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); |
| 327 | glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); | 354 | glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); |
| 328 | 355 | ||
| 329 | // draw the number of voxels we have | 356 | // draw the number of voxels we have |
| 330 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIndicesID); | 357 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); |
| 331 | glScalef(10, 10, 10); | 358 | glScalef(10, 10, 10); |
| 332 | glDrawElements(GL_TRIANGLES, 36 * voxelsRendered, GL_UNSIGNED_INT, 0); | 359 | glDrawElements(GL_TRIANGLES, 36 * _voxelsInArrays, GL_UNSIGNED_INT, 0); |
| 333 | 360 | ||
| 334 | // deactivate vertex and color arrays after drawing | 361 | // deactivate vertex and color arrays after drawing |
| 335 | glDisableClientState(GL_VERTEX_ARRAY); | 362 | glDisableClientState(GL_VERTEX_ARRAY); |
| @@ -350,12 +377,7 @@ void VoxelSystem::simulate(float deltaTime) { · 14 unmodified lines | |||
| 350 | 377 | ||
| 351 | int VoxelSystem::_nodeCount = 0; | 378 | int VoxelSystem::_nodeCount = 0; |
| 352 | 379 | ||
| 353 | bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraData) { | 380 | bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) { |
| 354 | |||
| 355 | // we do our operations on the way up! | ||
| 356 | if (down) { | ||
| 357 | return true; | ||
| 358 | } | ||
| 359 | 381 | ||
| 360 | _nodeCount++; | 382 | _nodeCount++; |
| 361 | if (node->isColored()) { | 383 | if (node->isColored()) { |
| @@ -370,17 +392,12 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraDa · 8 unmodified lines | |||
| 370 | 392 | ||
| 371 | void VoxelSystem::randomizeVoxelColors() { | 393 | void VoxelSystem::randomizeVoxelColors() { |
| 372 | _nodeCount = 0; | 394 | _nodeCount = 0; |
| 373 | tree->recurseTreeWithOperation(randomColorOperation); | 395 | _tree->recurseTreeWithOperation(randomColorOperation); |
| 374 | printLog("setting randomized true color for %d nodes\n",_nodeCount); | 396 | printLog("setting randomized true color for %d nodes\n",_nodeCount); |
| 375 | setupNewVoxelsForDrawing(); | 397 | setupNewVoxelsForDrawing(); |
| 376 | } | 398 | } |
| 377 | 399 | ||
| 378 | bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData) { | 400 | bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData) { |
| 379 | |||
| 380 | // we do our operations on the way up! | ||
| 381 | if (down) { | ||
| 382 | return true; | ||
| 383 | } | ||
| 384 | 401 | ||
| 385 | _nodeCount++; | 402 | _nodeCount++; |
| 386 | 403 | ||
| @@ -395,18 +412,12 @@ bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* · 8 unmodified lines | |||
| 395 | 412 | ||
| 396 | void VoxelSystem::falseColorizeRandom() { | 413 | void VoxelSystem::falseColorizeRandom() { |
| 397 | _nodeCount = 0; | 414 | _nodeCount = 0; |
| 398 | tree->recurseTreeWithOperation(falseColorizeRandomOperation); | 415 | _tree->recurseTreeWithOperation(falseColorizeRandomOperation); |
| 399 | printLog("setting randomized false color for %d nodes\n",_nodeCount); | 416 | printLog("setting randomized false color for %d nodes\n",_nodeCount); |
| 400 | setupNewVoxelsForDrawing(); | 417 | setupNewVoxelsForDrawing(); |
| 401 | } | 418 | } |
| 402 | 419 | ||
| 403 | bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraData) { | 420 | bool VoxelSystem::trueColorizeOperation(VoxelNode* node, void* extraData) { |
| 404 | |||
| 405 | // we do our operations on the way up! | ||
| 406 | if (down) { | ||
| 407 | return true; | ||
| 408 | } | ||
| 409 | |||
| 410 | _nodeCount++; | 421 | _nodeCount++; |
| 411 | node->setFalseColored(false); | 422 | node->setFalseColored(false); |
| 412 | return true; | 423 | return true; |
| @@ -414,19 +425,13 @@ bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraD · 1 unmodified line | |||
| 414 | 425 | ||
| 415 | void VoxelSystem::trueColorize() { | 426 | void VoxelSystem::trueColorize() { |
| 416 | _nodeCount = 0; | 427 | _nodeCount = 0; |
| 417 | tree->recurseTreeWithOperation(trueColorizeOperation); | 428 | _tree->recurseTreeWithOperation(trueColorizeOperation); |
| 418 | printLog("setting true color for %d nodes\n",_nodeCount); | 429 | printLog("setting true color for %d nodes\n",_nodeCount); |
| 419 | setupNewVoxelsForDrawing(); | 430 | setupNewVoxelsForDrawing(); |
| 420 | } | 431 | } |
| 421 | 432 | ||
| 422 | // Will false colorize voxels that are not in view | 433 | // Will false colorize voxels that are not in view |
| 423 | bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData) { | 434 | bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, void* extraData) { |
| 424 | |||
| 425 | // we do our operations on the way up! | ||
| 426 | if (down) { | ||
| 427 | return true; | ||
| 428 | } | ||
| 429 | |||
| 430 | const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData; | 435 | const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData; |
| 431 | 436 | ||
| 432 | _nodeCount++; | 437 | _nodeCount++; |
| @@ -448,25 +453,17 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* · 15 unmodified lines | |||
| 448 | 453 | ||
| 449 | void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) { | 454 | void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) { |
| 450 | _nodeCount = 0; | 455 | _nodeCount = 0; |
| 451 | tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum); | 456 | _tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum); |
| 452 | printLog("setting in view false color for %d nodes\n",_nodeCount); | 457 | printLog("setting in view false color for %d nodes\n",_nodeCount); |
| 453 | setupNewVoxelsForDrawing(); | 458 | setupNewVoxelsForDrawing(); |
| 454 | } | 459 | } |
| 455 | 460 | ||
| 456 | // Will false colorize voxels based on distance from view | 461 | // Will false colorize voxels based on distance from view |
| 457 | bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData) { | 462 | bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData) { |
| 458 | |||
| 459 | // we do our operations on the way up! | ||
| 460 | if (down) { | ||
| 461 | return true; | ||
| 462 | } | ||
| 463 | |||
| 464 | ViewFrustum* viewFrustum = (ViewFrustum*) extraData; | 463 | ViewFrustum* viewFrustum = (ViewFrustum*) extraData; |
| 465 | 464 | ||
| 466 | // only do this for truly colored voxels... | 465 | // only do this for truly colored voxels... |
| 467 | if (node->isColored()) { | 466 | if (node->isColored()) { |
| 468 | |||
| 469 | // We need our distance for both up and down | ||
| 470 | glm::vec3 nodePosition; | 467 | glm::vec3 nodePosition; |
| 471 | float* startVertex = firstVertexForCode(node->octalCode); | 468 | float* startVertex = firstVertexForCode(node->octalCode); |
| 472 | nodePosition.x = startVertex[0]; | 469 | nodePosition.x = startVertex[0]; |
| @@ -508,13 +505,7 @@ float VoxelSystem::_minDistance = FLT_MAX; · 35 unmodified lines | |||
| 508 | // Helper function will get the distance from view range, would be nice if you could just keep track | 505 | // Helper function will get the distance from view range, would be nice if you could just keep track |
| 509 | // of this as voxels are created and/or colored... seems like some transform math could do that so | 506 | // of this as voxels are created and/or colored... seems like some transform math could do that so |
| 510 | // we wouldn't need to do two passes of the tree | 507 | // we wouldn't need to do two passes of the tree |
| 511 | bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData) { | 508 | bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData) { |
| 512 | |||
| 513 | // we do our operations on the way up! | ||
| 514 | if (down) { | ||
| 515 | return true; | ||
| 516 | } | ||
| 517 | |||
| 518 | ViewFrustum* viewFrustum = (ViewFrustum*) extraData; | 509 | ViewFrustum* viewFrustum = (ViewFrustum*) extraData; |
| 519 | 510 | ||
| 520 | // only do this for truly colored voxels... | 511 | // only do this for truly colored voxels... |
| @@ -538,7 +529,7 @@ bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, · 17 unmodified lines | |||
| 538 | powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) + | 529 | powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) + |
| 539 | powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2)); | 530 | powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2)); |
| 540 | 531 | ||
| 541 | // on way down, calculate the range of distances | 532 | // calculate the range of distances |
| 542 | if (distance > _maxDistance) { | 533 | if (distance > _maxDistance) { |
| 543 | _maxDistance = distance; | 534 | _maxDistance = distance; |
| 544 | } | 535 | } |
| @@ -556,12 +547,14 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { · 11 unmodified lines | |||
| 556 | 547 | ||
| 557 | _maxDistance = 0.0; | 548 | _maxDistance = 0.0; |
| 558 | _minDistance = FLT_MAX; | 549 | _minDistance = FLT_MAX; |
| 559 | tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum); | 550 | _tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum); |
| 560 | printLog("determining distance range for %d nodes\n",_nodeCount); | 551 | printLog("determining distance range for %d nodes\n",_nodeCount); |
| 561 | 552 | ||
| 562 | _nodeCount = 0; | 553 | _nodeCount = 0; |
| 563 | 554 | ||
| 564 | tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); | 555 | _tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); |
| 565 | printLog("setting in distance false color for %d nodes\n",_nodeCount); | 556 | printLog("setting in distance false color for %d nodes\n",_nodeCount); |
| 566 | setupNewVoxelsForDrawing(); | 557 | setupNewVoxelsForDrawing(); |
| 567 | } | 558 | } |
| 559 | |||
| 560 | |||