Showing the changes to interface/src/VoxelSystem.cpp (1 of 2 files). Show all
Unified · Split
| @@ -42,7 +42,8 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- . · 41 unmodified lines | |||
| 42 | 4,5,6, 4,6,7 }; // Z+ . | 42 | 4,5,6, 4,6,7 }; // Z+ . |
| 43 | 43 | ||
| 44 | VoxelSystem::VoxelSystem() { | 44 | VoxelSystem::VoxelSystem() { |
| 45 | _voxelsInArrays = _voxelsUpdated = 0; | 45 | _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; |
| 46 | _alwaysRenderFullVBO = true; | ||
| 46 | _tree = new VoxelTree(); | 47 | _tree = new VoxelTree(); |
| 47 | pthread_mutex_init(&_bufferWriteLock, NULL); | 48 | pthread_mutex_init(&_bufferWriteLock, NULL); |
| 48 | pthread_mutex_init(&_voxelCleanupLock, NULL); | 49 | pthread_mutex_init(&_voxelCleanupLock, NULL); |
| @@ -61,7 +62,7 @@ VoxelSystem::~VoxelSystem() { · 12 unmodified lines | |||
| 61 | 62 | ||
| 62 | void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { | 63 | void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { |
| 63 | _tree->loadVoxelsFile(fileName, wantColorRandomizer); | 64 | _tree->loadVoxelsFile(fileName, wantColorRandomizer); |
| 64 | copyWrittenDataToReadArrays(); | 65 | setupNewVoxelsForDrawing(); |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) { | 68 | void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) { |
| @@ -130,7 +131,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 62 unmodified lines | |||
| 130 | if (0==strcmp(command,(char*)"erase all")) { | 131 | if (0==strcmp(command,(char*)"erase all")) { |
| 131 | printLog("got Z message == erase all\n"); | 132 | printLog("got Z message == erase all\n"); |
| 132 | _tree->eraseAllVoxels(); | 133 | _tree->eraseAllVoxels(); |
| 133 | _voxelsInArrays = 0; // better way to do this?? | 134 | _voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this?? |
| 134 | } | 135 | } |
| 135 | if (0==strcmp(command,(char*)"add scene")) { | 136 | if (0==strcmp(command,(char*)"add scene")) { |
| 136 | printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); | 137 | printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); |
| @@ -145,34 +146,41 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 8 unmodified lines | |||
| 145 | } | 146 | } |
| 146 | 147 | ||
| 147 | void VoxelSystem::setupNewVoxelsForDrawing() { | 148 | void VoxelSystem::setupNewVoxelsForDrawing() { |
| 148 | PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); // would like to include _voxelsInArrays, _voxelsUpdated | 149 | PerformanceWarning warn(_renderWarningsOn, "setupNewVoxelsForDrawing()"); // would like to include _voxelsInArrays, _voxelsUpdated |
| 149 | double start = usecTimestampNow(); | 150 | double start = usecTimestampNow(); |
| 150 | double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished); | 151 | double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0; |
| 151 | 152 | ||
| 152 | if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { | 153 | if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { |
| 153 | return; // bail early, it hasn't been long enough since the last time we ran | 154 | return; // bail early, it hasn't been long enough since the last time we ran |
| 154 | } | 155 | } |
| 156 | |||
| 157 | double sinceLastViewCulling = (start - _lastViewCulling) / 1000.0; | ||
| 155 | 158 | ||
| 156 | // If the view frustum has changed, since last time, then remove nodes that are out of view | 159 | // If the view frustum has changed, since last time, then remove nodes that are out of view |
| 157 | //if (hasViewChanged()) { | 160 | if ((sinceLastViewCulling >= VIEW_CULLING_RATE_IN_MILLISECONDS) && hasViewChanged()) { |
| 158 | // removeOutOfView(); | 161 | _lastViewCulling = start; |
| 159 | //} | 162 | removeOutOfView(); |
| 163 | } | ||
| 160 | 164 | ||
| 161 | if (_tree->isDirty()) { | 165 | if (_tree->isDirty()) { |
| 166 | PerformanceWarning warn(_renderWarningsOn, "calling... newTreeToArrays()"); | ||
| 162 | _callsToTreesToArrays++; | 167 | _callsToTreesToArrays++; |
| 168 | |||
| 169 | if (_alwaysRenderFullVBO) { | ||
| 170 | _voxelsInWriteArrays = 0; // reset our VBO | ||
| 171 | } | ||
| 163 | _voxelsUpdated = newTreeToArrays(_tree->rootNode); | 172 | _voxelsUpdated = newTreeToArrays(_tree->rootNode); |
| 164 | _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean | 173 | _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean |
| 165 | } else { | 174 | } else { |
| 166 | _voxelsUpdated = 0; | 175 | _voxelsUpdated = 0; |
| 167 | } | 176 | } |
| 177 | //printLog("setupNewVoxelsForDrawing() AFTER treeToArray _voxelsUpdated=%ld _voxelsDirty=%s\n", _voxelsUpdated, (_voxelsDirty ? "yes" : "no")); | ||
| 168 | if (_voxelsUpdated) { | 178 | if (_voxelsUpdated) { |
| 169 | _voxelsDirty=true; | 179 | _voxelsDirty=true; |
| 170 | } | 180 | } |
| 171 | 181 | ||
| 172 | if (_voxelsDirty) { | 182 | // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated |
| 173 | // copy the newly written data to the arrays designated for reading | 183 | copyWrittenDataToReadArrays(); |
| 174 | copyWrittenDataToReadArrays(); | ||
| 175 | } | ||
| 176 | 184 | ||
| 177 | double end = usecTimestampNow(); | 185 | double end = usecTimestampNow(); |
| 178 | double elapsedmsec = (end - start)/1000.0; | 186 | double elapsedmsec = (end - start)/1000.0; |
| @@ -185,16 +193,18 @@ void VoxelSystem::copyWrittenDataToReadArrays() { · 6 unmodified lines | |||
| 185 | if (_voxelsDirty && _voxelsUpdated) { | 193 | if (_voxelsDirty && _voxelsUpdated) { |
| 186 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it | 194 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it |
| 187 | pthread_mutex_lock(&_bufferWriteLock); | 195 | pthread_mutex_lock(&_bufferWriteLock); |
| 188 | int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); | 196 | int bytesOfVertices = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); |
| 189 | int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); | 197 | int bytesOfColors = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); |
| 190 | memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices); | 198 | memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices); |
| 191 | memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); | 199 | memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); |
| 200 | _voxelsInReadArrays = _voxelsInWriteArrays; | ||
| 192 | pthread_mutex_unlock(&_bufferWriteLock); | 201 | pthread_mutex_unlock(&_bufferWriteLock); |
| 193 | } | 202 | } |
| 194 | } | 203 | } |
| 195 | 204 | ||
| 196 | int VoxelSystem::newTreeToArrays(VoxelNode* node) { | 205 | int VoxelSystem::newTreeToArrays(VoxelNode* node) { |
| 197 | assert(_viewFrustum); // you must set up _viewFrustum before calling this | 206 | assert(_viewFrustum); // you must set up _viewFrustum before calling this |
| 207 | |||
| 198 | int voxelsUpdated = 0; | 208 | int voxelsUpdated = 0; |
| 199 | bool shouldRender = false; // assume we don't need to render it | 209 | bool shouldRender = false; // assume we don't need to render it |
| 200 | 210 | ||
| @@ -217,9 +227,39 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { · 16 unmodified lines | |||
| 217 | voxelsUpdated += newTreeToArrays(node->getChildAtIndex(i)); | 227 | voxelsUpdated += newTreeToArrays(node->getChildAtIndex(i)); |
| 218 | } | 228 | } |
| 219 | } | 229 | } |
| 220 | 230 | ||
| 231 | if (_alwaysRenderFullVBO) { | ||
| 232 | voxelsUpdated += newway__updateNodeInArray(node); | ||
| 233 | } else { | ||
| 234 | voxelsUpdated += oldway__updateNodeInArray(node); | ||
| 235 | } | ||
| 236 | node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered | ||
| 237 | return voxelsUpdated; | ||
| 238 | } | ||
| 239 | |||
| 240 | int VoxelSystem::newway__updateNodeInArray(VoxelNode* node) { | ||
| 241 | if (node->getShouldRender()) { | ||
| 242 | glm::vec3 startVertex = node->getCorner(); | ||
| 243 | float voxelScale = node->getScale(); | ||
| 244 | glBufferIndex nodeIndex = _voxelsInWriteArrays; | ||
| 245 | |||
| 246 | // populate the array with points for the 8 vertices | ||
| 247 | // and RGB color for each added vertex | ||
| 248 | for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { | ||
| 249 | GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); | ||
| 250 | GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); | ||
| 251 | *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); | ||
| 252 | *(writeColorsAt +j) = node->getColor()[j % 3]; | ||
| 253 | } | ||
| 254 | _voxelsInWriteArrays++; // our know vertices in the arrays | ||
| 255 | return 1; // rendered | ||
| 256 | } | ||
| 257 | return 0; // not-rendered | ||
| 258 | } | ||
| 259 | |||
| 260 | int VoxelSystem::oldway__updateNodeInArray(VoxelNode* node) { | ||
| 221 | // Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us | 261 | // Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... for us |
| 222 | if (node->isDirty() && (shouldRender || node->isKnownBufferIndex())) { | 262 | if (node->isDirty() && (node->getShouldRender() || node->isKnownBufferIndex())) { |
| 223 | glm::vec3 startVertex; | 263 | glm::vec3 startVertex; |
| 224 | float voxelScale = 0; | 264 | float voxelScale = 0; |
| 225 | 265 | ||
| @@ -239,7 +279,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { · 13 unmodified lines | |||
| 239 | if (node->isKnownBufferIndex()) { | 279 | if (node->isKnownBufferIndex()) { |
| 240 | nodeIndex = node->getBufferIndex(); | 280 | nodeIndex = node->getBufferIndex(); |
| 241 | } else { | 281 | } else { |
| 242 | nodeIndex = _voxelsInArrays; | 282 | nodeIndex = _voxelsInWriteArrays; |
| 243 | } | 283 | } |
| 244 | 284 | ||
| 245 | _voxelDirtyArray[nodeIndex] = true; | 285 | _voxelDirtyArray[nodeIndex] = true; |
| @@ -254,12 +294,11 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { · 8 unmodified lines | |||
| 254 | } | 294 | } |
| 255 | if (!node->isKnownBufferIndex()) { | 295 | if (!node->isKnownBufferIndex()) { |
| 256 | node->setBufferIndex(nodeIndex); | 296 | node->setBufferIndex(nodeIndex); |
| 257 | _voxelsInArrays++; // our know vertices in the arrays | 297 | _voxelsInWriteArrays++; // our know vertices in the arrays |
| 258 | } | 298 | } |
| 259 | voxelsUpdated++; | 299 | return 1; // updated! |
| 260 | } | 300 | } |
| 261 | node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered | 301 | return 0; // not-updated |
| 262 | return voxelsUpdated; | ||
| 263 | } | 302 | } |
| 264 | 303 | ||
| 265 | VoxelSystem* VoxelSystem::clone() const { | 304 | VoxelSystem* VoxelSystem::clone() const { |
| @@ -273,10 +312,12 @@ void VoxelSystem::init() { · 7 unmodified lines | |||
| 273 | _callsToTreesToArrays = 0; | 312 | _callsToTreesToArrays = 0; |
| 274 | _setupNewVoxelsForDrawingLastFinished = 0; | 313 | _setupNewVoxelsForDrawingLastFinished = 0; |
| 275 | _setupNewVoxelsForDrawingLastElapsed = 0; | 314 | _setupNewVoxelsForDrawingLastElapsed = 0; |
| 315 | _lastViewCulling = 0; | ||
| 276 | 316 | ||
| 277 | // When we change voxels representations in the arrays, we'll update this | 317 | // When we change voxels representations in the arrays, we'll update this |
| 278 | _voxelsDirty = false; | 318 | _voxelsDirty = false; |
| 279 | _voxelsInArrays = 0; | 319 | _voxelsInWriteArrays = 0; |
| 320 | _voxelsInReadArrays = 0; | ||
| 280 | _unusedArraySpace = 0; | 321 | _unusedArraySpace = 0; |
| 281 | 322 | ||
| 282 | // we will track individual dirty sections with this array of bools | 323 | // we will track individual dirty sections with this array of bools |
| @@ -348,31 +389,48 @@ void VoxelSystem::init() { · 65 unmodified lines | |||
| 348 | void VoxelSystem::updateVBOs() { | 389 | void VoxelSystem::updateVBOs() { |
| 349 | PerformanceWarning warn(_renderWarningsOn, "updateVBOs()"); // would like to include _callsToTreesToArrays | 390 | PerformanceWarning warn(_renderWarningsOn, "updateVBOs()"); // would like to include _callsToTreesToArrays |
| 350 | if (_voxelsDirty) { | 391 | if (_voxelsDirty) { |
| 351 | glBufferIndex segmentStart = 0; | 392 | if (_alwaysRenderFullVBO) { |
| 352 | glBufferIndex segmentEnd = 0; | 393 | glBufferIndex segmentStart = 0; |
| 353 | bool inSegment = false; | 394 | glBufferIndex segmentEnd = _voxelsInWriteArrays; |
| 354 | for (glBufferIndex i = 0; i < _voxelsInArrays; i++) { | 395 | |
| 355 | if (!inSegment) { | 396 | int segmentLength = (segmentEnd - segmentStart) + 1; |
| 356 | if (_voxelDirtyArray[i]) { | 397 | GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); |
| 357 | segmentStart = i; | 398 | GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); |
| 358 | inSegment = true; | 399 | GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); |
| 359 | _voxelDirtyArray[i] = false; // consider us clean! | 400 | glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); |
| 360 | } | 401 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); |
| 361 | } else { | 402 | segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); |
| 362 | if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) { | 403 | segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); |
| 363 | segmentEnd = i; | 404 | GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); |
| 364 | inSegment = false; | 405 | glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); |
| 365 | int segmentLength = (segmentEnd - segmentStart) + 1; | 406 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); |
| 366 | GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | 407 | } else { |
| 367 | GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | 408 | glBufferIndex segmentStart = 0; |
| 368 | GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | 409 | glBufferIndex segmentEnd = 0; |
| 369 | glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); | 410 | bool inSegment = false; |
| 370 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); | 411 | for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { |
| 371 | segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | 412 | if (!inSegment) { |
| 372 | segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | 413 | if (_voxelDirtyArray[i]) { |
| 373 | GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | 414 | segmentStart = i; |
| 374 | glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); | 415 | inSegment = true; |
| 375 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); | 416 | _voxelDirtyArray[i] = false; // consider us clean! |
| 417 | } | ||
| 418 | } else { | ||
| 419 | if (!_voxelDirtyArray[i] || (i == (_voxelsInWriteArrays - 1)) ) { | ||
| 420 | segmentEnd = i; | ||
| 421 | inSegment = false; | ||
| 422 | int segmentLength = (segmentEnd - segmentStart) + 1; | ||
| 423 | GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | ||
| 424 | GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | ||
| 425 | GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | ||
| 426 | glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); | ||
| 427 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); | ||
| 428 | segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | ||
| 429 | segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | ||
| 430 | GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | ||
| 431 | glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); | ||
| 432 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); | ||
| 433 | } | ||
| 376 | } | 434 | } |
| 377 | } | 435 | } |
| 378 | } | 436 | } |
| @@ -403,7 +461,7 @@ void VoxelSystem::render() { · 24 unmodified lines | |||
| 403 | // draw the number of voxels we have | 461 | // draw the number of voxels we have |
| 404 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); | 462 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); |
| 405 | glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); | 463 | glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); |
| 406 | glDrawElements(GL_TRIANGLES, 36 * _voxelsInArrays, GL_UNSIGNED_INT, 0); | 464 | glDrawElements(GL_TRIANGLES, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); |
| 407 | 465 | ||
| 408 | // deactivate vertex and color arrays after drawing | 466 | // deactivate vertex and color arrays after drawing |
| 409 | glDisableClientState(GL_VERTEX_ARRAY); | 467 | glDisableClientState(GL_VERTEX_ARRAY); |
| @@ -422,7 +480,7 @@ int VoxelSystem::_nodeCount = 0; · 12 unmodified lines | |||
| 422 | 480 | ||
| 423 | void VoxelSystem::killLocalVoxels() { | 481 | void VoxelSystem::killLocalVoxels() { |
| 424 | _tree->eraseAllVoxels(); | 482 | _tree->eraseAllVoxels(); |
| 425 | _voxelsInArrays = 0; // better way to do this?? | 483 | _voxelsInWriteArrays = _voxelsInReadArrays = 0; // better way to do this?? |
| 426 | //setupNewVoxelsForDrawing(); | 484 | //setupNewVoxelsForDrawing(); |
| 427 | } | 485 | } |
| 428 | 486 | ||