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 | 42 | 4,5,6, 4,6,7 }; // Z+ . |
| 43 | 43 | |
| 44 | 44 | VoxelSystem::VoxelSystem() { |
| 45 | − _voxelsInArrays = _voxelsUpdated = 0; | |
| 45 | + _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; | |
| 46 | + _alwaysRenderFullVBO = true; | |
| 46 | 47 | _tree = new VoxelTree(); |
| 47 | 48 | pthread_mutex_init(&_bufferWriteLock, NULL); |
| 48 | 49 | pthread_mutex_init(&_voxelCleanupLock, NULL); |
| @@ -61,7 +62,7 @@ VoxelSystem::~VoxelSystem() { · 12 unmodified lines | ||
| 61 | 62 | |
| 62 | 63 | void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { |
| 63 | 64 | _tree->loadVoxelsFile(fileName, wantColorRandomizer); |
| 64 | − copyWrittenDataToReadArrays(); | |
| 65 | + setupNewVoxelsForDrawing(); | |
| 65 | 66 | } |
| 66 | 67 | |
| 67 | 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 | 131 | if (0==strcmp(command,(char*)"erase all")) { |
| 131 | 132 | printLog("got Z message == erase all\n"); |
| 132 | 133 | _tree->eraseAllVoxels(); |
| 133 | − _voxelsInArrays = 0; // better way to do this?? | |
| 134 | + _voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this?? | |
| 134 | 135 | } |
| 135 | 136 | if (0==strcmp(command,(char*)"add scene")) { |
| 136 | 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 | 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 | 150 | double start = usecTimestampNow(); |
| 150 | − double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished); | |
| 151 | + double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0; | |
| 151 | 152 | |
| 152 | 153 | if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { |
| 153 | 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 | 159 | // If the view frustum has changed, since last time, then remove nodes that are out of view |
| 157 | − //if (hasViewChanged()) { | |
| 158 | − // removeOutOfView(); | |
| 159 | − //} | |
| 160 | + if ((sinceLastViewCulling >= VIEW_CULLING_RATE_IN_MILLISECONDS) && hasViewChanged()) { | |
| 161 | + _lastViewCulling = start; | |
| 162 | + removeOutOfView(); | |
| 163 | + } | |
| 160 | 164 | |
| 161 | 165 | if (_tree->isDirty()) { |
| 166 | + PerformanceWarning warn(_renderWarningsOn, "calling... newTreeToArrays()"); | |
| 162 | 167 | _callsToTreesToArrays++; |
| 168 | + | |
| 169 | + if (_alwaysRenderFullVBO) { | |
| 170 | + _voxelsInWriteArrays = 0; // reset our VBO | |
| 171 | + } | |
| 163 | 172 | _voxelsUpdated = newTreeToArrays(_tree->rootNode); |
| 164 | 173 | _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean |
| 165 | 174 | } else { |
| 166 | 175 | _voxelsUpdated = 0; |
| 167 | 176 | } |
| 177 | + //printLog("setupNewVoxelsForDrawing() AFTER treeToArray _voxelsUpdated=%ld _voxelsDirty=%s\n", _voxelsUpdated, (_voxelsDirty ? "yes" : "no")); | |
| 168 | 178 | if (_voxelsUpdated) { |
| 169 | 179 | _voxelsDirty=true; |
| 170 | 180 | } |
| 171 | 181 | |
| 172 | − if (_voxelsDirty) { | |
| 173 | − // copy the newly written data to the arrays designated for reading | |
| 174 | − copyWrittenDataToReadArrays(); | |
| 175 | − } | |
| 182 | + // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated | |
| 183 | + copyWrittenDataToReadArrays(); | |
| 176 | 184 | |
| 177 | 185 | double end = usecTimestampNow(); |
| 178 | 186 | double elapsedmsec = (end - start)/1000.0; |
| @@ -185,16 +193,18 @@ void VoxelSystem::copyWrittenDataToReadArrays() { · 6 unmodified lines | ||
| 185 | 193 | if (_voxelsDirty && _voxelsUpdated) { |
| 186 | 194 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it |
| 187 | 195 | pthread_mutex_lock(&_bufferWriteLock); |
| 188 | − int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); | |
| 189 | − int bytesOfColors = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); | |
| 196 | + int bytesOfVertices = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); | |
| 197 | + int bytesOfColors = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); | |
| 190 | 198 | memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices); |
| 191 | 199 | memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); |
| 200 | + _voxelsInReadArrays = _voxelsInWriteArrays; | |
| 192 | 201 | pthread_mutex_unlock(&_bufferWriteLock); |
| 193 | 202 | } |
| 194 | 203 | } |
| 195 | 204 | |
| 196 | 205 | int VoxelSystem::newTreeToArrays(VoxelNode* node) { |
| 197 | 206 | assert(_viewFrustum); // you must set up _viewFrustum before calling this |
| 207 | + | |
| 198 | 208 | int voxelsUpdated = 0; |
| 199 | 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 | 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 | 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 | 263 | glm::vec3 startVertex; |
| 224 | 264 | float voxelScale = 0; |
| 225 | 265 | |
| @@ -239,7 +279,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { · 13 unmodified lines | ||
| 239 | 279 | if (node->isKnownBufferIndex()) { |
| 240 | 280 | nodeIndex = node->getBufferIndex(); |
| 241 | 281 | } else { |
| 242 | − nodeIndex = _voxelsInArrays; | |
| 282 | + nodeIndex = _voxelsInWriteArrays; | |
| 243 | 283 | } |
| 244 | 284 | |
| 245 | 285 | _voxelDirtyArray[nodeIndex] = true; |
| @@ -254,12 +294,11 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { · 8 unmodified lines | ||
| 254 | 294 | } |
| 255 | 295 | if (!node->isKnownBufferIndex()) { |
| 256 | 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 | |
| 262 | − return voxelsUpdated; | |
| 301 | + return 0; // not-updated | |
| 263 | 302 | } |
| 264 | 303 | |
| 265 | 304 | VoxelSystem* VoxelSystem::clone() const { |
| @@ -273,10 +312,12 @@ void VoxelSystem::init() { · 7 unmodified lines | ||
| 273 | 312 | _callsToTreesToArrays = 0; |
| 274 | 313 | _setupNewVoxelsForDrawingLastFinished = 0; |
| 275 | 314 | _setupNewVoxelsForDrawingLastElapsed = 0; |
| 315 | + _lastViewCulling = 0; | |
| 276 | 316 | |
| 277 | 317 | // When we change voxels representations in the arrays, we'll update this |
| 278 | 318 | _voxelsDirty = false; |
| 279 | − _voxelsInArrays = 0; | |
| 319 | + _voxelsInWriteArrays = 0; | |
| 320 | + _voxelsInReadArrays = 0; | |
| 280 | 321 | _unusedArraySpace = 0; |
| 281 | 322 | |
| 282 | 323 | // we will track individual dirty sections with this array of bools |
| @@ -348,31 +389,48 @@ void VoxelSystem::init() { · 65 unmodified lines | ||
| 348 | 389 | void VoxelSystem::updateVBOs() { |
| 349 | 390 | PerformanceWarning warn(_renderWarningsOn, "updateVBOs()"); // would like to include _callsToTreesToArrays |
| 350 | 391 | if (_voxelsDirty) { |
| 351 | − glBufferIndex segmentStart = 0; | |
| 352 | − glBufferIndex segmentEnd = 0; | |
| 353 | − bool inSegment = false; | |
| 354 | − for (glBufferIndex i = 0; i < _voxelsInArrays; i++) { | |
| 355 | − if (!inSegment) { | |
| 356 | − if (_voxelDirtyArray[i]) { | |
| 357 | − segmentStart = i; | |
| 358 | − inSegment = true; | |
| 359 | − _voxelDirtyArray[i] = false; // consider us clean! | |
| 360 | − } | |
| 361 | − } else { | |
| 362 | − if (!_voxelDirtyArray[i] || (i == (_voxelsInArrays - 1)) ) { | |
| 363 | − segmentEnd = i; | |
| 364 | − inSegment = false; | |
| 365 | − int segmentLength = (segmentEnd - segmentStart) + 1; | |
| 366 | − GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | |
| 367 | − GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | |
| 368 | − GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | |
| 369 | − glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); | |
| 370 | − glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); | |
| 371 | − segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | |
| 372 | − segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | |
| 373 | − GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | |
| 374 | − glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); | |
| 375 | − glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); | |
| 392 | + if (_alwaysRenderFullVBO) { | |
| 393 | + glBufferIndex segmentStart = 0; | |
| 394 | + glBufferIndex segmentEnd = _voxelsInWriteArrays; | |
| 395 | + | |
| 396 | + int segmentLength = (segmentEnd - segmentStart) + 1; | |
| 397 | + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | |
| 398 | + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); | |
| 399 | + GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | |
| 400 | + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); | |
| 401 | + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); | |
| 402 | + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | |
| 403 | + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); | |
| 404 | + GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); | |
| 405 | + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); | |
| 406 | + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); | |
| 407 | + } else { | |
| 408 | + glBufferIndex segmentStart = 0; | |
| 409 | + glBufferIndex segmentEnd = 0; | |
| 410 | + bool inSegment = false; | |
| 411 | + for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { | |
| 412 | + if (!inSegment) { | |
| 413 | + if (_voxelDirtyArray[i]) { | |
| 414 | + segmentStart = i; | |
| 415 | + inSegment = true; | |
| 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 | 461 | // draw the number of voxels we have |
| 404 | 462 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); |
| 405 | 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 | 466 | // deactivate vertex and color arrays after drawing |
| 409 | 467 | glDisableClientState(GL_VERTEX_ARRAY); |
| @@ -422,7 +480,7 @@ int VoxelSystem::_nodeCount = 0; · 12 unmodified lines | ||
| 422 | 480 | |
| 423 | 481 | void VoxelSystem::killLocalVoxels() { |
| 424 | 482 | _tree->eraseAllVoxels(); |
| 425 | − _voxelsInArrays = 0; // better way to do this?? | |
| 483 | + _voxelsInWriteArrays = _voxelsInReadArrays = 0; // better way to do this?? | |
| 426 | 484 | //setupNewVoxelsForDrawing(); |
| 427 | 485 | } |
| 428 | 486 | |