From bbf4f889d8e829fd4536de0d8ad94c58f9a61473 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Mon, 3 Feb 2014 09:45:12 -0500 Subject: [PATCH 01/31] Completed worklist job #19486 Job #19486 Don't render the duplicate triangles between adjacent voxels. Added checkable item to "developer" menu to activate/deactivate cull shared faces. Cull all shared voxel faces regardless of distribution in the octree. Includes leaf to leaf, leaf to non-leaf, and non-leaf to non-leaf comparison of contiguous faces. Added new GL primitive renderer to manage the transfer of cube faces from the voxel system to GL. Added some useful classes for queue and lock management. Modified statistics collection to report number of completely culled nodes. Extra debugging info also includes the interior occlusions bit mask of leaf voxels. --- interface/CMakeLists.txt | 2 +- interface/src/AutoLock.h | 84 +++ interface/src/Menu.cpp | 7 + interface/src/Menu.h | 1 + interface/src/Mutex.h | 146 +++++ interface/src/PrimitiveRenderer.cpp | 722 ++++++++++++++++++++++ interface/src/PrimitiveRenderer.h | 419 +++++++++++++ interface/src/Queue.h | 272 ++++++++ interface/src/Threading.h | 78 +++ interface/src/VoxelSystem.cpp | 604 +++++++++++++++--- interface/src/VoxelSystem.h | 15 +- libraries/octree/src/Octree.cpp | 22 + libraries/octree/src/Octree.h | 7 + libraries/octree/src/OctreeElement.h | 13 + libraries/voxels/src/VoxelTreeElement.cpp | 7 +- libraries/voxels/src/VoxelTreeElement.h | 37 +- 16 files changed, 2344 insertions(+), 92 deletions(-) create mode 100644 interface/src/AutoLock.h create mode 100644 interface/src/Mutex.h create mode 100644 interface/src/PrimitiveRenderer.cpp create mode 100644 interface/src/PrimitiveRenderer.h create mode 100644 interface/src/Queue.h create mode 100644 interface/src/Threading.h diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 6af6ed478d..0c7d3d16fa 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -40,7 +40,7 @@ if (WIN32) # which are not accessible on windows without glew or some other dynamic linking mechanism set(GLEW_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external/glew) set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${GLEW_ROOT_PATH}) - include_directories(SYSTEM ${GLEW_ROOT_PATH}/include) + include_directories(SYSTEM ${GLEW_ROOT_PATH}/include ${GLUT_ROOT_PATH}/include) #set(GL_HEADERS "#define GLEW_STATIC\n#define FREEGLUT_STATIC\n#define FREEGLUT_LIB_PRAGMAS 0\n#include \n#include \n#include \n#include ") set(GL_HEADERS "#define GLEW_STATIC\n#include \n#include \n#include ") diff --git a/interface/src/AutoLock.h b/interface/src/AutoLock.h new file mode 100644 index 0000000000..875fbd5954 --- /dev/null +++ b/interface/src/AutoLock.h @@ -0,0 +1,84 @@ +/** + * @file AutoLock.h + * A simple locking class featuring templated mutex policy and mutex barrier + * activation/deactivation constructor/destructor. + * + * @author Norman Crafts + * @copyright 2014, All rights reserved. + */ +#ifndef __AUTOLOCK_H__ +#define __AUTOLOCK_H__ + +#include "Mutex.h" + +/** + * @class AutoLock + */ +template +< + class MutexPolicy = Mutex +> +class AutoLock +{ +public: + /** Dependency injection constructor + * AutoLock constructor with client mutex injection + */ + AutoLock( + MutexPolicy & client ///< Client mutex + ); + + /** Dependency injection constructor + * AutoLock constructor with client mutex injection + */ + AutoLock( + MutexPolicy *client ///< Client mutex + ); + + ~AutoLock(); + +private: + /** Default constructor prohibited to API user + */ + AutoLock(); + + /** Copy constructor prohibited to API user + */ + AutoLock( + AutoLock const & copy + ); + +private: + MutexPolicy &_mutex; ///< Client mutex +}; + + +template +inline +AutoLock::AutoLock( + MutexPolicy &mutex + ) : + _mutex(mutex) +{ + _mutex.lock(); +} + +template +inline +AutoLock::AutoLock( + MutexPolicy *mutex + ) : + _mutex(*mutex) +{ + _mutex.lock(); +} + +template +inline +AutoLock::~AutoLock() +{ + _mutex.unlock(); +} + + +#endif // __AUTOLOCK_H__ diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8fd268938e..ed9a3fbba8 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -438,6 +438,13 @@ Menu::Menu() : appInstance->getVoxels(), SLOT(trueColorize())); + addCheckableActionToQMenuAndActionHash(renderDebugMenu, + MenuOption::CullSharedFaces, + Qt::CTRL | Qt::SHIFT | Qt::Key_C, + false, + appInstance->getVoxels(), + SLOT(cullSharedFaces())); + addDisabledActionAndSeparator(renderDebugMenu, "Coverage Maps"); addActionToQMenuAndActionHash(renderDebugMenu, MenuOption::FalseColorOccluded, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 03149ce07c..0ef205afbd 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -168,6 +168,7 @@ namespace MenuOption { const QString CopyVoxels = "Copy"; const QString CoverageMap = "Render Coverage Map"; const QString CoverageMapV2 = "Render Coverage Map V2"; + const QString CullSharedFaces = "Cull shared faces"; const QString CutVoxels = "Cut"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; diff --git a/interface/src/Mutex.h b/interface/src/Mutex.h new file mode 100644 index 0000000000..4fd7ecf9ab --- /dev/null +++ b/interface/src/Mutex.h @@ -0,0 +1,146 @@ +/** + * @file Mutex.h + * An operating system independent simple wrapper to mutex services. + * + * @author: Norman Crafts + * @copyright 2014, All rights reserved. + */ +#ifndef __MUTEX_H__ +#define __MUTEX_H__ + +#ifdef LINUX +#include +#include +#endif + +/** + * @class Mutex + * + * This class is an OS independent delegate pattern providing access + * to simple OS dependent mutex services. Assume the mutex service is + * non-reentrant. + */ +class Mutex +{ +public: + /** Default constructor + */ + Mutex(); + + ~Mutex(); + + /** Lock the mutex barrier + * First competing thread will capture the mutex and block all + * other threads. + */ + void lock(); + + /** Unlock the mutex barrier + * Mutex owner releases the mutex and allow competing threads to try to capture. + */ + void unlock(); + +private: + /** Copy constructor prohibited to API user + */ + Mutex( + Mutex const & copy + ); + +private: + +#ifdef _DEBUG + int _lockCt; +#endif //_DEBUG + +#ifdef WIN32 + CRITICAL_SECTION _mutex; +#endif // WIN32 + +#ifdef LINUX + pthread_mutex_t _mutex; +#endif // LINUX +}; + + +#ifdef WIN32 + +inline +Mutex::Mutex() +#ifdef _DEBUG + : + _lockCt(0) +#endif +{ + InitializeCriticalSection(&_mutex); +} + +inline +Mutex::~Mutex() +{ + DeleteCriticalSection(&_mutex); +} + +inline +void Mutex::lock() +{ + EnterCriticalSection(&_mutex); + #ifdef _DEBUG + _lockCt++; + #endif // _DEBUG +} + +inline +void Mutex::unlock() +{ + #ifdef _DEBUG + _lockCt--; + #endif // _DEBUG + LeaveCriticalSection(&_mutex); +} + +#endif // WIN32 + +#ifdef LINUX + +inline +Mutex::Mutex() +#ifdef _DEBUG + : + _lockCt(0) +#endif +{ + int err; + pthread_mutexattr_t attrib; + + err = pthread_mutexattr_init(&attrib); + err = pthread_mutex_init(&_mutex, &attrib); + err = pthread_mutexattr_destroy(&attrib); +} + +inline +Mutex::~Mutex() +{ + pthread_mutex_destroy(&_mutex); +} + +inline +void Mutex::lock() +{ + pthread_mutex_lock(&_mutex); + #ifdef _DEBUG + _lockCt++; + #endif // _DEBUG +} + +inline +void Mutex::unlock() +{ + #ifdef _DEBUG + _lockCt--; + #endif // _DEBUG + pthread_mutex_unlock(&_mutex); +} + +#endif // LINUX +#endif // __MUTEX_H__ diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp new file mode 100644 index 0000000000..a285058a7c --- /dev/null +++ b/interface/src/PrimitiveRenderer.cpp @@ -0,0 +1,722 @@ +/** + * @file PrimitiveRenderer.cpp + * A geometric primitive renderer. + * + * @author: Norman Crafts + * @copyright 2014, High Fidelity, Inc. All rights reserved. + */ +#include "InterfaceConfig.h" +#include "OctreeElement.h" +#include "PrimitiveRenderer.h" + +Primitive::Primitive() +{} + +Primitive::~Primitive() +{} + +// Simple dispatch between API and SPI + +VertexElementList const & Primitive::vertexElements() const +{ + return vVertexElements(); +} + +VertexElementIndexList & Primitive::vertexElementIndices() +{ + return vVertexElementIndices(); +} + +TriElementList & Primitive::triElements() +{ + return vTriElements(); +} + +void Primitive::releaseVertexElements() +{ + vReleaseVertexElements(); +} + + +Cube::Cube( + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ) +{ + initialize(x, y, z, s, r, g, b, faceExclusions); +} + +Cube::~Cube() +{ + terminate(); +} + +void Cube::initialize( + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ) +{ + initializeVertices(x, y, z, s, r, g, b, faceExclusions); + initializeTris(faceExclusions); +} + +void Cube::terminate() +{ + terminateTris(); + terminateVertices(); +} + +void Cube::initializeVertices( + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ) +{ + for (int i = 0; i < 24; i++) + { + // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. + if (~faceExclusions & s_faceIndexToHalfSpaceMask[i >> 2]) + //if (~0x00 & s_faceIndexToHalfSpaceMask[i >> 2]) + //if (faceExclusions & s_faceIndexToHalfSpaceMask[i >> 2]) + { + VertexElement *v = new VertexElement(); + if (v) + { + // Construct vertex position + v->position.x = x + s * s_vertexIndexToConstructionVector[i][0]; + v->position.y = y + s * s_vertexIndexToConstructionVector[i][1]; + v->position.z = z + s * s_vertexIndexToConstructionVector[i][2]; + + // Construct vertex normal + v->normal.x = s_vertexIndexToNormalVector[i >> 2][0]; + v->normal.y = s_vertexIndexToNormalVector[i >> 2][1]; + v->normal.z = s_vertexIndexToNormalVector[i >> 2][2]; + + // Construct vertex color +//#define FALSE_COLOR +#ifndef FALSE_COLOR + v->color.r = r; + v->color.g = g; + v->color.b = b; + v->color.a = 255; +#else + static unsigned char falseColor[6][3] = { + 192, 0, 0, // Bot + 0, 192, 0, // Top + 0, 0, 192, // Right + 192, 0, 192, // Left + 192, 192, 0, // Near + 192, 192, 192 // Far + }; + v->color.r = falseColor[i >> 2][0]; + v->color.g = falseColor[i >> 2][1]; + v->color.b = falseColor[i >> 2][2]; + v->color.a = 255; +#endif + + // Add vertex element to list + _vertices.push_back(v); + } + } + } +} + +void Cube::terminateVertices() +{ + VertexElementList::iterator it = _vertices.begin(); + VertexElementList::iterator end = _vertices.end(); + + for ( ; it != end; ++it) + { + delete *it; + } + _vertices.clear(); +} + +void Cube::initializeTris( + unsigned char faceExclusions + ) +{ + int index = 0; + for (int i = 0; i < 6; i++) + { + // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. + // uncomment this line to exclude shared faces: + if (~faceExclusions & s_faceIndexToHalfSpaceMask[i]) + // uncomment this line to load all faces: if (~0x00 & s_faceIndexToHalfSpaceMask[i]) + // uncomment this line to include shared faces: if (faceExclusions & s_faceIndexToHalfSpaceMask[i]) + { + int start = index; + // Create the triangulated face, two tris, six indices referencing four vertices, both + // with cw winding order, such that: + + // A-B + // |\| + // D-C + + // Store triangle ABC + + TriElement *tri = new TriElement(); + if (tri) + { + tri->indices[0] = index++; + tri->indices[1] = index++; + tri->indices[2] = index; + + // Add tri element to list + _tris.push_back(tri); + } + + // Now store triangle ACD + tri = new TriElement(); + if (tri) + { + tri->indices[0] = start; + tri->indices[1] = index++; + tri->indices[2] = index++; + + // Add tri element to list + _tris.push_back(tri); + } + } + } +} + +void Cube::terminateTris() +{ + TriElementList::iterator it = _tris.begin(); + TriElementList::iterator end = _tris.end(); + + for ( ; it != end; ++it) + { + delete *it; + } + _tris.clear(); +} + +VertexElementList const & Cube::vVertexElements() const +{ + return _vertices; +} + +VertexElementIndexList & Cube::vVertexElementIndices() +{ + return _vertexIndices; +} + +TriElementList & Cube::vTriElements() +{ + return _tris; +} + +void Cube::vReleaseVertexElements() +{ + terminateVertices(); +} + +unsigned char Cube::s_faceIndexToHalfSpaceMask[6] = { + OctreeElement::HalfSpace::Bottom, + OctreeElement::HalfSpace::Top, + OctreeElement::HalfSpace::Right, + OctreeElement::HalfSpace::Left, + OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Far, +}; + +#define CW_CONSTRUCTION +#ifdef CW_CONSTRUCTION +// Construction vectors ordered such that the vertices of each face are +// CW in a right-handed coordinate system with B-L-N at 0,0,0. +float Cube::s_vertexIndexToConstructionVector[24][3] = { + // Bottom + { 0,0,0 }, + { 1,0,0 }, + { 1,0,1 }, + { 0,0,1 }, + // Top + { 0,1,0 }, + { 0,1,1 }, + { 1,1,1 }, + { 1,1,0 }, + // Right + { 1,0,0 }, + { 1,1,0 }, + { 1,1,1 }, + { 1,0,1 }, + // Left + { 0,0,0 }, + { 0,0,1 }, + { 0,1,1 }, + { 0,1,0 }, + // Near + { 0,0,0 }, + { 0,1,0 }, + { 1,1,0 }, + { 1,0,0 }, + // Far + { 0,0,1 }, + { 1,0,1 }, + { 1,1,1 }, + { 0,1,1 }, +}; +#else // CW_CONSTRUCTION +// Construction vectors ordered such that the vertices of each face are +// CCW in a right-handed coordinate system with B-L-N at 0,0,0. +float Cube::s_vertexIndexToConstructionVector[24][3] = { + // Bottom + { 0,0,0 }, + { 0,0,1 }, + { 1,0,1 }, + { 1,0,0 }, + // Top + { 0,1,0 }, + { 1,1,0 }, + { 1,1,1 }, + { 0,1,1 }, + // Right + { 1,0,0 }, + { 1,0,1 }, + { 1,1,1 }, + { 1,1,0 }, + // Left + { 0,0,0 }, + { 0,1,0 }, + { 0,1,1 }, + { 0,0,1 }, + // Near + { 0,0,0 }, + { 1,0,0 }, + { 1,1,0 }, + { 0,1,0 }, + // Far + { 0,0,1 }, + { 0,1,1 }, + { 1,1,1 }, + { 1,0,1 }, +}; +#endif + +// Normals for a right-handed coordinate system +float Cube::s_vertexIndexToNormalVector[6][3] = { + { 0,-1, 0 }, // Bottom + { 0, 1, 0 }, // Top + { 1, 0, 0 }, // Right + { -1, 0, 0 }, // Left + { 0, 0,-1 }, // Near + { 0, 0, 1 }, // Far +}; + +Renderer::Renderer() +{} + +Renderer::~Renderer() +{} + +// Simple dispatch between API and SPI +int Renderer::add( + Primitive *primitive + ) +{ + return vAdd(primitive); +} + +void Renderer::remove( + int id + ) +{ + vRemove(id); +} + +void Renderer::render() +{ + vRender(); +} + +PrimitiveRenderer::PrimitiveRenderer( + int maxCount + ) : + _maxCount(maxCount), + _vertexElementCount(0), + _maxVertexElementCount(maxCount), + _triElementCount(0), + _maxTriElementCount(maxCount), + _primitiveCount(0), + + _triBufferId(0), + _vertexBufferId(0), + + _gpuMemoryUsage(0), + _cpuMemoryUsage(0) + +{ + initialize(); +} + +PrimitiveRenderer::~PrimitiveRenderer() +{ + terminate(); +} + +void PrimitiveRenderer::initialize() +{ + initializeGL(); + initializeBookkeeping(); +} + +void PrimitiveRenderer::initializeGL() +{ + glGenBuffers(1, &_triBufferId); + glGenBuffers(1, &_vertexBufferId); + + // Set up the element array buffer containing the index ids + int size = _maxCount * sizeof(GLint) * 3; + _gpuMemoryUsage += size; + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + // Set up the array buffer in the form of array of structures + // I chose AOS because it maximizes the amount of data tranferred + // by a single glBufferSubData call. + size = _maxCount * sizeof(VertexElement); + _gpuMemoryUsage += size; + + glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); + glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // Initialize the first vertex element in the buffer to all zeros, the + // degenerate case + _vertexElementCount = 1; + _triElementCount = 1; + + VertexElement v; + memset(&v, 0, sizeof(v)); + + transferVertexElement(0, &v); + deconstructTriElement(0); + + GLint err = glGetError(); +} + +void PrimitiveRenderer::initializeBookkeeping() +{ + _primitiveCount = 1; + _cpuMemoryUsage = sizeof(PrimitiveRenderer); +} + +void PrimitiveRenderer::terminate() +{ + terminateBookkeeping(); + terminateGL(); +} + +void PrimitiveRenderer::terminateGL() +{ + glDeleteBuffers(1, &_vertexBufferId); + glDeleteBuffers(1, &_triBufferId); + GLint err = glGetError(); +} + +void PrimitiveRenderer::terminateBookkeeping() +{ + // Drain all of the queues, stop updating the counters + while (_availableVertexElementIndex.remove()); + while (_availableTriElementIndex.remove()); + while (_deconstructTriElementIndex.remove()); + + std::map::iterator it = _indexToPrimitiveMap.begin(); + std::map::iterator end = _indexToPrimitiveMap.end(); + + for ( ; it != end; ++it) + { + Primitive *primitive = it->second; + delete primitive; + } +} + +int PrimitiveRenderer::vAdd( + Primitive *primitive + ) +{ + int index = getAvailablePrimitiveIndex(); + if (index != 0) + { + try + { + // Take ownership of primitive, including responsibility + // for destruction + _indexToPrimitiveMap[index] = primitive; + constructElements(primitive); + + // No need to keep an extra copy of the vertices + primitive->releaseVertexElements(); + } + catch(...) + { + // STL failed, recycle the index + _availablePrimitiveIndex.add(index); + index = 0; + } + } + return index; +} + +void PrimitiveRenderer::vRemove( + int index + ) +{ + try + { + // Locate the primitive by id in the associative map + std::map::iterator it = _indexToPrimitiveMap.find(index); + if (it != _indexToPrimitiveMap.end()) + { + Primitive *primitive = it->second; + if (primitive) + { + _indexToPrimitiveMap[index] = 0; + deconstructElements(primitive); + _availablePrimitiveIndex.add(index); + } + // Not necessary to remove the item from the associative map, because + // the index is going to be re-used, but if you want to... uncomment the following: + //_indexToPrimitiveMap.erase(it); + } + } + catch(...) + { + // STL failed + } +} + +void PrimitiveRenderer::constructElements( + Primitive *primitive + ) +{ + // Load vertex elements + VertexElementIndexList & vertexElementIndexList = primitive->vertexElementIndices(); + { + VertexElementList const & vertices = primitive->vertexElements(); + VertexElementList::const_iterator it = vertices.begin(); + VertexElementList::const_iterator end = vertices.end(); + + for ( ; it != end; ++it ) + { + int index = getAvailableVertexElementIndex(); + if (index != 0) + { + vertexElementIndexList.push_back(index); + VertexElement *vertex = *it; + transferVertexElement(index, vertex); + } + } + } + + // Load tri elements + { + TriElementList & tris = primitive->triElements(); + TriElementList::iterator it = tris.begin(); + TriElementList::iterator end = tris.end(); + + for ( ; it != end; ++it) + { + TriElement *tri = *it; + int index = getAvailableTriElementIndex(); + if (index != 0) + { + int k; + k = tri->indices[0]; + tri->indices[0] = vertexElementIndexList[k]; + + k = tri->indices[1]; + tri->indices[1] = vertexElementIndexList[k]; + + k = tri->indices[2]; + tri->indices[2] = vertexElementIndexList[k]; + + tri->id = index; + transferTriElement(index, tri->indices); + } + } + } +} + +void PrimitiveRenderer::deconstructElements( + Primitive *primitive + ) +{ + // Schedule the tri elements of the face for deconstruction + { + TriElementList & tris = primitive->triElements(); + TriElementList::iterator it = tris.begin(); + TriElementList::iterator end = tris.end(); + + for ( ; it != end; ++it) + { + TriElement *tri = *it; + + // Put the tri element index into decon queue + _deconstructTriElementIndex.add(tri->id); + } + } + // Return the vertex element index to the available queue, it is not necessary + // to zero the data + { + VertexElementIndexList & vertexIndexList = primitive->vertexElementIndices(); + VertexElementIndexList::iterator it = vertexIndexList.begin(); + VertexElementIndexList::iterator end = vertexIndexList.end(); + + for ( ; it != end; ++it) + { + int index = *it; + + // Put the vertex element index into the available queue + _availableVertexElementIndex.add(index); + } + } + + // destroy primitive + delete primitive; +} + +int PrimitiveRenderer::getAvailablePrimitiveIndex() +{ + // Check the available primitive index queue first for an available index. + int index = _availablePrimitiveIndex.remove(); + // Remember that the primitive index 0 is used not used. + if (index == 0) + { + // There are no primitive indices available from the queue, + // make one up + index = _primitiveCount++; + } + return index; +} + +int PrimitiveRenderer::getAvailableVertexElementIndex() +{ + // Check the available vertex element queue first for an available index. + int index = _availableVertexElementIndex.remove(); + // Remember that the vertex element 0 is used for degenerate triangles. + if (index == 0) + { + // There are no vertex elements available from the queue, + // grab one from the end of the list + if (_vertexElementCount < _maxVertexElementCount) + index = _vertexElementCount++; + } + return index; +} + +int PrimitiveRenderer::getAvailableTriElementIndex() +{ + // Check the deconstruct tri element queue first for an available index. + int index = _deconstructTriElementIndex.remove(); + // Remember that the tri element 0 is used for degenerate triangles. + if (index == 0) + { + // There are no tri elements in the deconstruct tri element queue that are reusable. + // Check the available tri element queue. + index = _availableTriElementIndex.remove(); + if (index == 0) + { + // There are no reusable tri elements available from any queue, + // grab one from the end of the list + if (_triElementCount < _maxTriElementCount) + index = _triElementCount++; + } + } + return index; +} + +void PrimitiveRenderer::deconstructTriElement( + int idx + ) +{ + // Set the element to the degenerate case. + int degenerate[3] = { 0, 0, 0 }; + transferTriElement(idx, degenerate); + +} + +void PrimitiveRenderer::transferVertexElement( + int idx, + VertexElement *vertex + ) +{ + glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); + glBufferSubData(GL_ARRAY_BUFFER, idx * sizeof(VertexElement), sizeof(VertexElement), vertex); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void PrimitiveRenderer::transferTriElement( + int idx, + int tri[3] +) +{ + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, idx * sizeof(GLint) * 3, sizeof(GLint) * 3, tri); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void PrimitiveRenderer::vRender() +{ + // Now would be an appropriate time to set the element array buffer ids + // scheduled for deconstruction to the degenerate case. + int id; + while ((id = _deconstructTriElementIndex.remove())) + { + deconstructTriElement(id); + _availableTriElementIndex.add(id); + } + + // The application uses clockwise winding for the definition of front face, but I + // arbitrarily chose counter-clockwise (that is the gl default) to construct the triangulation + // so... + //glFrontFace(GL_CCW); + glEnable(GL_CULL_FACE); + + glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(VertexElement), 0); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, sizeof(VertexElement), (GLvoid const *)12); + + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexElement), (GLvoid const *)24); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + GLint err = glGetError(); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); + glDrawElements(GL_TRIANGLES, 3 * _triElementCount, GL_UNSIGNED_INT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + glDisable(GL_CULL_FACE); + + // TODO: does the interface ever change the winding order? + //glFrontFace(GL_CW); + err = glGetError(); +} + diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/PrimitiveRenderer.h new file mode 100644 index 0000000000..e54842c229 --- /dev/null +++ b/interface/src/PrimitiveRenderer.h @@ -0,0 +1,419 @@ +/** + * @file PrimitiveRenderer.h + * A geometric primitive renderer. + * + * @author: Norman Crafts + * @copyright 2014, High Fidelity, Inc. All rights reserved. + */ + +#ifndef __interface__PrimitiveRenderer__ +#define __interface__PrimitiveRenderer__ + +#include +#include + +/** Vertex element structure + * Using the array of structures approach to specifying + * vertex data to GL cuts down on the calls to glBufferSubData + */ +typedef + struct __VertexElement + { + struct __position { + float x; + float y; + float z; + } position; + struct __normal { + float x; + float y; + float z; + } normal; + struct __color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } color; + } VertexElement; + +/** Triangle element index structure + * Specify the vertex indices of the triangle and its element index. + */ +typedef +struct __TriElement +{ + int indices[3]; + int id; + +} TriElement; + +typedef std::vector > VertexElementList; +typedef std::vector > VertexElementIndexList; +typedef std::vector > TriElementList; + +/** + * @class Primitive + * Primitive Interface class + * Abstract class for accessing vertex and tri elements of geometric primitives + * + */ +class Primitive +{ +public: + virtual ~Primitive(); + + // API methods go here + + /** Vertex element accessor + * @return A list of vertex elements of the primitive + */ + VertexElementList const & vertexElements() const; + + /** Vertex element index accessor + * @return A list of vertex element indices of the primitive + */ + VertexElementIndexList & vertexElementIndices(); + + /** Tri element accessor + * @return A list of tri elements of the primitive + */ + TriElementList & triElements(); + + /** Release vertex elements + */ + void releaseVertexElements(); + +protected: + /** Default constructor prohibited to API user, restricted to service implementer + */ + Primitive(); + +private: + /** Copy constructor prohibited + */ + Primitive( + Primitive const & prim + ); + + // SPI methods are defined here + + /** Vertex element accessor + * Service implementer to provide private override for this method + * in derived class + */ + virtual VertexElementList const & vVertexElements() const = 0; + + /** Vertex element index accessor + * Service implementer to provide private override for this method + * in derived class + */ + virtual VertexElementIndexList & vVertexElementIndices() = 0; + + /** Tri element accessor + * Service implementer to provide private override for this method + * in derived class + */ + virtual TriElementList & vTriElements() = 0; + + /** Release vertex elements + */ + virtual void vReleaseVertexElements() = 0; + +}; + + +/** + * @class Cube + * Class for accessing the vertex and tri elements of a cube + */ +class Cube: + public Primitive +{ +public: + /** Configuration dependency injection constructor + */ + Cube( + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faces + ); + + ~Cube(); + +private: + /** Copy constructor prohibited + */ + Cube ( + Cube const & cube + ); + + void initialize( + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ); + + void terminate(); + + void initializeVertices( + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ); + + void terminateVertices(); + + void initializeTris( + unsigned char faceExclusions + ); + + void terminateTris(); + + // SPI virtual override methods go here + + VertexElementList const & vVertexElements() const; + VertexElementIndexList & vVertexElementIndices(); + TriElementList & vTriElements(); + void vReleaseVertexElements(); + + +private: + VertexElementList _vertices; ///< Vertex element list + VertexElementIndexList _vertexIndices; ///< Vertex element index list + TriElementList _tris; ///< Tri element list + + static unsigned char s_faceIndexToHalfSpaceMask[6]; + static float s_vertexIndexToConstructionVector[24][3]; + static float s_vertexIndexToNormalVector[6][3]; + +}; + + +/** + * @class Renderer + * GL renderer interface class + * Abstract class for rendering geometric primitives in GL + */ +class Renderer +{ +public: + virtual ~Renderer(); + + // API methods go here + + /** Add primitive to renderer database + */ + int add( + Primitive *primitive ///< Pointer to primitive + ); + + /** Remove primitive from renderer database + */ + void remove( + int id ///< Primitive id + ); + + /** Render primitive database + * The render method assumes appropriate GL context and state has + * already been provided for + */ + void render(); + +protected: + /** Default constructor prohibited to API user, restricted to service implementer + */ + Renderer(); + +private: + /** Copy constructor prohibited + */ + Renderer( + Renderer const & primitive + ); + + // SPI methods are defined here + + /** Add primitive to renderer database + * Service implementer to provide private override for this method + * in derived class + */ + virtual int vAdd( + Primitive *primitive ///< Pointer to primitive + ) = 0; + + /** Remove primitive from renderer database + * Service implementer to provide private override for this method + * in derived class + */ + virtual void vRemove( + int id ///< Primitive id + ) = 0; + + /** Render primitive database + * Service implementer to provide private virtual override for this method + * in derived class + */ + virtual void vRender() = 0; +}; + +/** + * @class PrimitiveRenderer + * Renderer implementation class for the rendering of geometric primitives + * using GL element array and GL array buffers + */ +class PrimitiveRenderer : + public Renderer +{ +public: + /** Configuration dependency injection constructor + */ + PrimitiveRenderer( + int maxCount + ); + + ~PrimitiveRenderer(); + +private: + /** Default constructor prohibited + */ + PrimitiveRenderer(); + + /** Copy constructor prohibited + */ + PrimitiveRenderer( + PrimitiveRenderer const & renderer + ); + + void initialize(); + void terminate(); + + /** Allocate and initialize GL buffers + */ + void initializeGL(); + + /** Terminate and deallocate GL buffers + */ + void terminateGL(); + + void initializeBookkeeping(); + void terminateBookkeeping(); + + /** Construct the elements of the faces of the primitive + */ + void constructElements( + Primitive *primitive + ); + + /** Deconstruct the elements of the faces of the primitive + */ + void deconstructElements( + Primitive *primitive + ); + + /** Deconstruct the triangle element from the GL buffer + */ + void deconstructTriElement( + int idx + ); + + /** Transfer the vertex element to the GL buffer + */ + void transferVertexElement( + int idx, + VertexElement *vertex + ); + + /** Transfer the triangle element to the GL buffer + */ + void transferTriElement( + int idx, + int tri[3] + ); + + /** Get available primitive index + * Get an available primitive index from either the recycling + * queue or incrementing the counter + */ + int getAvailablePrimitiveIndex(); + + /** Get available vertex element index + * Get an available vertex element index from either the recycling + * queue or incrementing the counter + */ + int getAvailableVertexElementIndex(); + + /** Get available triangle element index + * Get an available triangle element index from either the elements + * scheduled for deconstruction queue, the recycling + * queue or incrementing the counter + */ + int getAvailableTriElementIndex(); + + // SPI virtual override methods go here + + /** Add primitive to renderer database + */ + int vAdd( + Primitive *primitive + ); + + /** Remove primitive from renderer database + */ + void vRemove( + int id + ); + + /** Render triangle database + */ + void vRender(); + +private: + + int _maxCount; + + // GL related parameters + + GLuint _triBufferId; ///< GL element array buffer id + GLuint _vertexBufferId; ///< GL vertex array buffer id + + // Book keeping parameters + + int _vertexElementCount; ///< Count of vertices + int _maxVertexElementCount; ///< Max count of vertices + + int _triElementCount; ///< Count of triangles + int _maxTriElementCount; ///< Max count of triangles + + std::map _indexToPrimitiveMap; ///< Associative map between index and primitive + int _primitiveCount; ///< Count of primitives + + Queue _availablePrimitiveIndex; ///< Queue of primitive indices available + Queue _availableVertexElementIndex; ///< Queue of vertex element indices available + Queue _availableTriElementIndex; ///< Queue of triangle element indices available + Queue _deconstructTriElementIndex; ///< Queue of triangle element indices requiring GL update + + // Statistics parameters, not necessary for proper operation + + int _gpuMemoryUsage; + int _cpuMemoryUsage; + +}; + + +#endif diff --git a/interface/src/Queue.h b/interface/src/Queue.h new file mode 100644 index 0000000000..777af7e145 --- /dev/null +++ b/interface/src/Queue.h @@ -0,0 +1,272 @@ +/** + * @file Queue.h + * An efficient FIFO queue featuring lock-free interaction between + * producer and consumer. + * + * @author: Norman Crafts + * @copyright 2014, All rights reserved. + */ +#ifndef __QUEUE_H__ +#define __QUEUE_H__ + +#include "AutoLock.h" +#include "Mutex.h" +#include "Threading.h" + +/** + * @class Queue + * + * A template based, efficient first-in/first-out queue featuring lock free + * access between producer and consumer. + */ +template +< + class Client, // Managed client class + template class ProducerThreadingPolicy = MultiThreaded, + template class ConsumerThreadingPolicy = MultiThreaded, + class ProducerMutexPolicy = Mutex, + class ConsumerMutexPolicy = Mutex +> +class Queue +{ +public: + /** Default constructor + */ + Queue(); + + ~Queue(); + + /** Add an object of managed client class to the tail of the queue + */ + void add( + Client item + ); + + /** Remove an object of managed client class from the head of the queue + */ + Client remove(); + + /** Peek at an object of managed client class at the head of the queue + * but do not remove it. + */ + Client peek(); + + /** Is the queue empty? + */ + bool isEmpty(); + +private: + struct __node + { + /** Default node constructor + */ + __node() : + _item(), + _next(0) + {} + + /** Item injection constructor + */ + __node( + Client item + ) : + _item(item), + _next(0) + {} + + Client _item; + struct __node *_next; + }; + + static const int s_cacheLineSize = 64; ///< Cache line size (in bytes) of standard Intel architecture + char pad0[s_cacheLineSize]; ///< Padding to eliminate cache line contention between threads + + ProducerThreadingPolicy _producerGuard; + char pad1[s_cacheLineSize - sizeof(ProducerThreadingPolicy)]; + + ConsumerThreadingPolicy _consumerGuard; + char pad2[s_cacheLineSize - sizeof(ConsumerThreadingPolicy)]; + + struct __node *_first; ///< Queue management + char pad3[s_cacheLineSize - sizeof(struct __node *)]; + + struct __node *_last; ///< Queue management + char pad4[s_cacheLineSize - sizeof(struct __node *)]; +}; + + + + + + + + +template + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > +Queue + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::Queue() +{ + _first = new __node(); + _last = _first; + memset(pad0, 0, sizeof(pad0)); + memset(pad1, 0, sizeof(pad1)); + memset(pad2, 0, sizeof(pad2)); + memset(pad3, 0, sizeof(pad3)); + memset(pad4, 0, sizeof(pad4)); +} + +template + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > +Queue + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::~Queue() +{ + AutoLock > lock(_consumerGuard); + while (_first) + { + struct __node *t = _first; + _first = t->_next; + delete t; + } +} + + +template + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > +void Queue + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::add( + Client item + ) +{ + struct __node *n = new __node(item); + AutoLock > lock(_producerGuard); + _last->_next = n; + _last = n; +} + + + +template + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > +Client Queue + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::remove() +{ + AutoLock > lock(_consumerGuard); + struct __node *next = _first->_next; + if (next) + { + struct __node *first = _first; + Client item = next->_item; + next->_item = 0; + _first = next; + delete first; + return item; + } + return 0; +} + + + +template + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > +Client Queue + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::peek() +{ + AutoLock > lock(_consumerGuard); + struct __node *next = _first->_next; + if (next) + { + Client item = next->_item; + return item; + } + return 0; +} + + + +template + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > +bool Queue + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::isEmpty() +{ + bool empty = true; + AutoLock > lock(_consumerGuard); + struct __node *next = _first->_next; + if (next) + empty = false; + + return empty; +} + +#endif // __QUEUE_H__ diff --git a/interface/src/Threading.h b/interface/src/Threading.h new file mode 100644 index 0000000000..2684199437 --- /dev/null +++ b/interface/src/Threading.h @@ -0,0 +1,78 @@ +/** + * @file Threading.h + * A delegate pattern to encapsulate threading policy semantics. + * + * @author: Norman Crafts + * @copyright 2014, All rights reserved. + */ +#ifndef __THREADING_H__ +#define __THREADING_H__ + +/** + * @class SingleThreaded + */ +template +< + class MutexPolicy = Mutex ///< Mutex policy +> +class SingleThreaded +{ +public: + + void lock(); + + void unlock(); +}; + +/** + * @class MultiThreaded + */ +template +< + class MutexPolicy = Mutex ///< Mutex policy +> +class MultiThreaded +{ +public: + + void lock(); + + void unlock(); + +private: + MutexPolicy _mutex; +}; + + + + +template +inline +void SingleThreaded::lock() +{} + +template +inline +void SingleThreaded::unlock() +{} + + + + + +template +inline +void MultiThreaded::lock() +{ + _mutex.lock(); +} + +template +inline +void MultiThreaded::unlock() +{ + _mutex.unlock(); +} + + +#endif // __THREADING_H__ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index c5071570d5..cfc83e8b56 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -60,7 +60,9 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) : NodeData(), _treeScale(treeScale), _maxVoxels(maxVoxels), - _initialized(false) { + _initialized(false), + _usePrimitiveRenderer(false), + _renderer(0) { _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; _writeRenderFullVBO = true; @@ -102,12 +104,13 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _inhideOutOfView = false; _treeIsBusy = false; + } void VoxelSystem::elementDeleted(OctreeElement* element) { VoxelTreeElement* voxel = (VoxelTreeElement*)element; if (voxel->getVoxelSystem() == this) { - if (_voxelsInWriteArrays != 0) { + if ((_voxelsInWriteArrays != 0) || _usePrimitiveRenderer) { forceRemoveNodeFromArrays(voxel); } else { if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { @@ -212,16 +215,16 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) { } } if (!inList) { - // make the index available for next node that needs to be drawn - _freeIndexLock.lock(); - _freeIndexes.push_back(index); - _freeIndexLock.unlock(); + // make the index available for next node that needs to be drawn + _freeIndexLock.lock(); + _freeIndexes.push_back(index); + _freeIndexLock.unlock(); - // make the VBO slot "invisible" in case this slot is not used - const glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); - const float voxelScale = 0; - const nodeColor BLACK = {0, 0, 0, 0}; - updateArraysDetails(index, startVertex, voxelScale, BLACK); + // make the VBO slot "invisible" in case this slot is not used + const glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); + const float voxelScale = 0; + const nodeColor BLACK = {0, 0, 0, 0}; + updateArraysDetails(index, startVertex, voxelScale, BLACK); } } @@ -250,6 +253,8 @@ VoxelSystem::~VoxelSystem() { cleanupVoxelMemory(); delete _tree; + + _renderer = 0; } void VoxelSystem::setMaxVoxels(int maxVoxels) { @@ -258,12 +263,12 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) { } bool wasInitialized = _initialized; if (wasInitialized) { - clearAllNodesBufferIndex(); - cleanupVoxelMemory(); + clearAllNodesBufferIndex(); + cleanupVoxelMemory(); } _maxVoxels = maxVoxels; if (wasInitialized) { - initVoxelMemory(); + initVoxelMemory(); } if (wasInitialized) { forceRedrawEntireTree(); @@ -281,6 +286,7 @@ void VoxelSystem::setUseVoxelShader(bool useVoxelShader) { cleanupVoxelMemory(); } _useVoxelShader = useVoxelShader; + _usePrimitiveRenderer = false; if (wasInitialized) { initVoxelMemory(); } @@ -345,7 +351,8 @@ void VoxelSystem::cleanupVoxelMemory() { _writeVoxelShaderData = _readVoxelShaderData = NULL; - } else { + } else + if (! _usePrimitiveRenderer) { // Destroy glBuffers glDeleteBuffers(1, &_vboVerticesID); glDeleteBuffers(1, &_vboColorsID); @@ -366,8 +373,11 @@ void VoxelSystem::cleanupVoxelMemory() { _writeVerticesArray = NULL; _readColorsArray = NULL; _writeColorsArray = NULL; - } + else { + delete _renderer; + _renderer = 0; + } delete[] _writeVoxelDirtyArray; delete[] _readVoxelDirtyArray; _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL; @@ -452,7 +462,8 @@ void VoxelSystem::initVoxelMemory() { _readVoxelShaderData = new VoxelShaderVBOData[_maxVoxels]; _memoryUsageRAM += (sizeof(VoxelShaderVBOData) * _maxVoxels); - } else { + } else + if (! _usePrimitiveRenderer) { // Global Normals mode uses a technique of not including normals on any voxel vertices, and instead // rendering the voxel faces in 6 passes that use a global call to glNormal3f() @@ -496,7 +507,6 @@ void VoxelSystem::initVoxelMemory() { _readColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels]; _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); - // create our simple fragment shader if we're the first system to init if (!_perlinModulateProgram.isLinked()) { switchToResourcesParentIfRequired(); @@ -516,6 +526,27 @@ void VoxelSystem::initVoxelMemory() { _shadowMapProgram.release(); } } + else { + _renderer = new PrimitiveRenderer(_maxVoxels); + // create our simple fragment shader if we're the first system to init + if (!_perlinModulateProgram.isLinked()) { + switchToResourcesParentIfRequired(); + _perlinModulateProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/perlin_modulate.vert"); + _perlinModulateProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/perlin_modulate.frag"); + _perlinModulateProgram.link(); + + _perlinModulateProgram.bind(); + _perlinModulateProgram.setUniformValue("permutationNormalTexture", 0); + _perlinModulateProgram.release(); + + _shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/shadow_map.frag"); + _shadowMapProgram.link(); + + _shadowMapProgram.bind(); + _shadowMapProgram.setUniformValue("shadowMap", 0); + _shadowMapProgram.release(); + } + } _initialized = true; @@ -655,8 +686,15 @@ void VoxelSystem::setupNewVoxelsForDrawing() { }; PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); _callsToTreesToArrays++; + if (_writeRenderFullVBO) { - clearFreeBufferIndexes(); + if (_usePrimitiveRenderer) { + delete _renderer; + _renderer = new PrimitiveRenderer(_maxVoxels); + } + else { + clearFreeBufferIndexes(); + } } _voxelsUpdated = newTreeToArrays(_tree->getRoot()); _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean @@ -672,17 +710,24 @@ void VoxelSystem::setupNewVoxelsForDrawing() { _voxelsUpdated = 0; } - // lock on the buffer write lock so we can't modify the data when the GPU is reading it - _bufferWriteLock.lock(); + if (_usePrimitiveRenderer) { + if (_voxelsUpdated) { + _voxelsDirty=true; + } + } + else { + // lock on the buffer write lock so we can't modify the data when the GPU is reading it + _bufferWriteLock.lock(); - if (_voxelsUpdated) { - _voxelsDirty=true; - } + if (_voxelsUpdated) { + _voxelsDirty=true; + } - // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated - copyWrittenDataToReadArrays(didWriteFullVBO); + // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated + copyWrittenDataToReadArrays(didWriteFullVBO); - _bufferWriteLock.unlock(); + _bufferWriteLock.unlock(); + } uint64_t end = usecTimestampNow(); int elapsedmsec = (end - start) / 1000; @@ -710,23 +755,28 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { return; // bail early, it hasn't been long enough since the last time we ran } - // lock on the buffer write lock so we can't modify the data when the GPU is reading it - { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" ); - _bufferWriteLock.lock(); - } + if (_usePrimitiveRenderer) { + _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty + _voxelsUpdated = 0; + } + else { + // lock on the buffer write lock so we can't modify the data when the GPU is reading it + { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" ); + _bufferWriteLock.lock(); + } - _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty + _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty - // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated - copyWrittenDataToReadArrays(_writeRenderFullVBO); + // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated + copyWrittenDataToReadArrays(_writeRenderFullVBO); - // after... - _voxelsUpdated = 0; - - _bufferWriteLock.unlock(); + // after... + _voxelsUpdated = 0; + _bufferWriteLock.unlock(); + } uint64_t end = usecTimestampNow(); int elapsedmsec = (end - start) / 1000; _setupNewVoxelsForDrawingLastFinished = end; @@ -946,14 +996,24 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelTreeElement* node) { return 0; } - // if the node is not in the VBOs then we have nothing to do! - if (node->isKnownBufferIndex()) { - // If this node has not yet been written to the array, then add it to the end of the array. - glBufferIndex nodeIndex = node->getBufferIndex(); - node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - freeBufferIndex(nodeIndex); // NOTE: This will make the node invisible! - return 1; // updated! - } + if (_usePrimitiveRenderer) { + int primitiveIndex = node->getPrimitiveIndex(); + if (primitiveIndex) { + _renderer->remove(primitiveIndex); + node->setPrimitiveIndex(0); + return 1; + } + } + else { + // if the node is not in the VBOs then we have nothing to do! + if (node->isKnownBufferIndex()) { + // If this node has not yet been written to the array, then add it to the end of the array. + glBufferIndex nodeIndex = node->getBufferIndex(); + node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); + freeBufferIndex(nodeIndex); // NOTE: This will make the node invisible! + return 1; // updated! + } + } return 0; // not-updated } @@ -980,20 +1040,46 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo if (forceDraw || node->isDirty()) { // If we're should render, use our legit location and scale, if (node->getShouldRender()) { - glm::vec3 startVertex = node->getCorner(); - float voxelScale = node->getScale(); + glm::vec3 startVertex = node->getCorner(); + float voxelScale = node->getScale(); + nodeColor const & color = node->getColor(); - glBufferIndex nodeIndex = GLBUFFER_INDEX_UNKNOWN; - if (reuseIndex && node->isKnownBufferIndex()) { - nodeIndex = node->getBufferIndex(); - } else { - nodeIndex = getNextBufferIndex(); - node->setBufferIndex(nodeIndex); - node->setVoxelSystem(this); - } - // populate the array with points for the 8 vertices and RGB color for each added vertex - updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); - return 1; // updated! + if (_usePrimitiveRenderer) { + int primitiveIndex = node->getPrimitiveIndex(); + if (primitiveIndex) { + _renderer->remove(primitiveIndex); + node->setPrimitiveIndex(0); + } + else { + node->setVoxelSystem(this); + } + inspectForInteriorOcclusionsOperation(node, 0); + + if (node->getInteriorOcclusions() != OctreeElement::HalfSpace::All) + { + Cube *cube = new Cube( + startVertex.x, startVertex.y, startVertex.z, voxelScale, + color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX], + node->getInteriorOcclusions()); + if (cube) { + primitiveIndex = _renderer->add(cube); + node->setPrimitiveIndex(primitiveIndex); + } + } + } + else { + glBufferIndex nodeIndex = GLBUFFER_INDEX_UNKNOWN; + if (reuseIndex && node->isKnownBufferIndex()) { + nodeIndex = node->getBufferIndex(); + } else { + nodeIndex = getNextBufferIndex(); + node->setBufferIndex(nodeIndex); + node->setVoxelSystem(this); + } + // populate the array with points for the 8 vertices and RGB color for each added vertex + updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); + } + return 1; // updated! } else { // If we shouldn't render, and we're in reuseIndex mode, then free our index, this only operates // on nodes with known index values, so it's safe to call for any node. @@ -1140,15 +1226,17 @@ void VoxelSystem::updateVBOs() { }; // would like to include _callsToTreesToArrays PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); - if (_voxelsDirty) { - if (_readRenderFullVBO) { - updateFullVBOs(); - } else { - updatePartialVBOs(); - } - _voxelsDirty = false; - _readRenderFullVBO = false; - } + if (! _usePrimitiveRenderer) { + if (_voxelsDirty) { + if (_readRenderFullVBO) { + updateFullVBOs(); + } else { + updatePartialVBOs(); + } + _voxelsDirty = false; + _readRenderFullVBO = false; + } + } _callsToTreesToArrays = 0; // clear it } @@ -1274,7 +1362,8 @@ void VoxelSystem::render(bool texture) { glDisableVertexAttribArray(attributeLocation); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); } - } else { + } else + if (!_usePrimitiveRenderer) { PerformanceWarning warn(showWarnings, "render().. TRIANGLES..."); { @@ -1348,6 +1437,12 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } } + else { + applyScaleAndBindProgram(texture); + _renderer->render(); + removeScaleAndReleaseProgram(texture); + + } } void VoxelSystem::applyScaleAndBindProgram(bool texture) { @@ -1411,6 +1506,7 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; voxel->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); + voxel->setPrimitiveIndex(0); return true; } @@ -1424,6 +1520,215 @@ void VoxelSystem::clearAllNodesBufferIndex() { } } +bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData) { + _nodeCount++; + VoxelTreeElement* voxel = (VoxelTreeElement*)element; + + // Nothing to do at the leaf level + if (voxel->isLeaf()) { + return false; + } + + // Bit mask of occluded shared faces indexed by child + unsigned char occludedSharedFace[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + // Traverse all pair combinations of children + for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { + + VoxelTreeElement *childA = voxel->getChildAtIndex(i); + if (childA) { + + // Get the child A's occluding faces, for a leaf that will be + // all six voxel faces, and for a non leaf, that will be + // all faces which are completely covered by four child octants. + unsigned char exteriorOcclusionsA = childA->getExteriorOcclusions(); + + if (exteriorOcclusionsA == 0) { + // There is nothing to be done with this child, next... + continue; + } + + for (int j = i; --j >= 0; ) { + + VoxelTreeElement *childB = voxel->getChildAtIndex(j); + if (childB) { + + // Get child B's occluding faces + unsigned char exteriorOcclusionsB = childB->getExteriorOcclusions(); + + if (exteriorOcclusionsB == 0) { + // There is nothing to be done with this child, next... + continue; + } + + // Determine the shared halfspace partition between siblings A and B, + // i.e., near/far, left/right, or top/bottom + unsigned char partition = octantIndexToSharedBitMask[i][j] & + exteriorOcclusionsA & exteriorOcclusionsB; + + // Determine which face of each sibling is occluded. + // Note the intentionally crossed indicies. It is necessary because + // the octantIndexToBitMask is a partition occupancy mask. For + // example, if the near-left-top (NLT) and near-left-bottom (NLB) child voxels + // exist, the shared partition is top-bottom (TB), and thus the occluded + // shared face of the NLT voxel is its bottom face. + occludedSharedFace[i] |= (partition & octantIndexToBitMask[j]); + occludedSharedFace[j] |= (partition & octantIndexToBitMask[i]); + } + } + // Combine this voxel's interior excluded shared face only to those children which are coincident + // with the excluded face. + occludedSharedFace[i] |= (voxel->getInteriorOcclusions() & octantIndexToBitMask[i]); + + // Inform the child + childA->setInteriorOcclusions(occludedSharedFace[i]); + if (occludedSharedFace[i]) { + //const glm::vec3& v = voxel->getCorner(); + //float s = voxel->getScale(); + + //qDebug("Child %d of voxel at %f %f %f size: %f has %02x occlusions", i, v.x, v.y, v.z, s, occludedSharedFace[i]); + } + } + } + return true; +} + +bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, void* extraData) { + _nodeCount++; + VoxelTreeElement* voxel = (VoxelTreeElement*)element; + + // Nothing to do at the leaf level + if (voxel->isLeaf()) { + return false; + } + + // Count of exterior occluding faces of this voxel element indexed + // by half space partition + unsigned int exteriorOcclusionsCt[6] = { 0, 0, 0, 0, 0, 0 }; + + // Traverse all children + for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { + + VoxelTreeElement *child = voxel->getChildAtIndex(i); + if (child) { + // Get the child's occluding faces, for a leaf, that will be + // all six voxel faces, and for a non leaf, that will be + // all faces which are completely covered by four child octants. + unsigned char exteriorOcclusionsOfChild = child->getExteriorOcclusions(); + exteriorOcclusionsOfChild &= octantIndexToBitMask[i]; + + for (int j = 6; --j >= 0; ) { + + // Determine if the halfspace partition indexed by 1 << j is + // present in the exterior occlusions of the child. + unsigned char partition = exteriorOcclusionsOfChild & (1 << j); + + if (partition) { + exteriorOcclusionsCt[j]++; + } + } + } + } + { + // Derive the exterior occlusions of the voxel elements from the exclusions + // of its children + unsigned char exteriorOcclusions = 0; + for (int i = 6; --i >= 0; ) { + if (exteriorOcclusionsCt[i] == 4) { + + // Exactly four octants qualify for full exterior occlusion + exteriorOcclusions |= (1 << i); + } + } + + // Inform the voxel element + voxel->setExteriorOcclusions(exteriorOcclusions); + + if (exteriorOcclusions == OctreeElement::HalfSpace::All) { + //const glm::vec3& v = voxel->getCorner(); + //float s = voxel->getScale(); + + //qDebug("Completely occupied voxel at %f %f %f size: %f", v.x, v.y, v.z, s); + + // TODO: All of the exterior faces of this voxel element are + // occluders, which means that this element is completely + // occupied. Hence, the subtree from this node could be + // pruned and replaced by a leaf voxel, if the visible + // properties of the children are the same + } + else + if (exteriorOcclusions) { + //const glm::vec3& v = voxel->getCorner(); + //float s = voxel->getScale(); + + //qDebug("Partially occupied voxel at %f %f %f size: %f with %02x", v.x, v.y, v.z, s, exteriorOcclusions); + } + } + return true; +} + +bool VoxelSystem::clearOcclusionsOperation(OctreeElement* element, void* extraData) { + _nodeCount++; + VoxelTreeElement* voxel = (VoxelTreeElement*)element; + + bool rc; + if (voxel->isLeaf()) { + + // By definition the the exterior faces of a leaf voxel are + // always occluders. + voxel->setExteriorOcclusions(OctreeElement::HalfSpace::All); + + // And the sibling occluders + voxel->setInteriorOcclusions(0); + rc = false; + } + else { + voxel->setExteriorOcclusions(0); + voxel->setInteriorOcclusions(0); + rc = true; + } + + return rc; +} + +void VoxelSystem::cullSharedFaces() { + _nodeCount = 0; + + if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { + cleanupVoxelMemory(); + _useVoxelShader = false; + _usePrimitiveRenderer = true; + initVoxelMemory(); + clearAllNodesBufferIndex(); + lockTree(); + _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); + _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); + unlockTree(); + + _nodeCount = 0; + lockTree(); + _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); + unlockTree(); + qDebug("culling shared faces in %d nodes", _nodeCount); + } + else { + cleanupVoxelMemory(); + _usePrimitiveRenderer = false; + initVoxelMemory(); + clearAllNodesBufferIndex(); + lockTree(); + _tree->recurseTreeWithOperation(clearOcclusionsOperation); + unlockTree(); + + + qDebug("unculling shared faces in %d nodes", _nodeCount); + } + _writeRenderFullVBO = true; + _tree->setDirtyBit(); + setupNewVoxelsForDrawing(); + +} + bool VoxelSystem::forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData) { _nodeCount++; element->setDirtyBit(); @@ -1997,7 +2302,7 @@ bool VoxelSystem::hideAllSubTreeOperation(OctreeElement* element, void* extraDat } args->nodesOutside++; - if (voxel->isKnownBufferIndex()) { + if (voxel->isKnownBufferIndex() || voxel->getPrimitiveIndex()) { args->nodesRemoved++; bool falseColorize = false; if (falseColorize) { @@ -2039,7 +2344,7 @@ bool VoxelSystem::showAllSubTreeOperation(OctreeElement* element, void* extraDat bool shouldRender = voxel->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale, boundaryLevelAdjust); voxel->setShouldRender(shouldRender); - if (shouldRender && !voxel->isKnownBufferIndex()) { + if (shouldRender && !(voxel->isKnownBufferIndex() || voxel->getPrimitiveIndex())) { bool falseColorize = false; if (falseColorize) { voxel->setFalseColor(0,0,255); // false colorize @@ -2047,6 +2352,12 @@ bool VoxelSystem::showAllSubTreeOperation(OctreeElement* element, void* extraDat // These are both needed to force redraw... voxel->setDirtyBit(); voxel->markWithChangedTime(); + // and this? + { + VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; + thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->updateNodeInArrays(voxel, true, true); + thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); + } args->nodesShown++; } @@ -2128,7 +2439,7 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData // if the child node INTERSECTs the view, then we want to check to see if it thinks it should render // if it should render but is missing it's VBO index, then we want to flip it on, and we can stop recursing from // here because we know will block any children anyway - if (voxel->getShouldRender() && !voxel->isKnownBufferIndex()) { + if (voxel->getShouldRender() && !(voxel->isKnownBufferIndex() || voxel->getPrimitiveIndex())) { voxel->setDirtyBit(); // will this make it draw? args->nodesShown++; return false; @@ -2225,7 +2536,9 @@ public: nodesInVBONotShouldRender(0), nodesInVBOOverExpectedMax(0), duplicateVBOIndex(0), - leafNodes(0) + leafNodes(0), + culledLeafNodes(0), + nodesInPrimitiveRenderer(0) { hasIndexFound = new bool[maxVoxels]; memset(hasIndexFound, false, maxVoxels * sizeof(bool)); @@ -2244,6 +2557,8 @@ public: unsigned long nodesInVBOOverExpectedMax; unsigned long duplicateVBOIndex; unsigned long leafNodes; + unsigned long culledLeafNodes; ///< Number of completely culled nodes because of face sharing + unsigned long nodesInPrimitiveRenderer; unsigned long expectedMax; @@ -2258,6 +2573,9 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v if (voxel->isLeaf()) { args->leafNodes++; + if (voxel->getInteriorOcclusions() == OctreeElement::HalfSpace::All) { + args->culledLeafNodes++; + } } if (voxel->isColored()) { @@ -2272,15 +2590,25 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v args->dirtyNodes++; } - if (voxel->isKnownBufferIndex()) { - args->nodesInVBO++; - unsigned long nodeIndex = voxel->getBufferIndex(); + unsigned long nodeIndex = 0; + if (voxel->isKnownBufferIndex()) { + args->nodesInVBO++; + nodeIndex = voxel->getBufferIndex(); + } + + if (voxel->getPrimitiveIndex()) { + args->nodesInPrimitiveRenderer++; + nodeIndex = voxel->getPrimitiveIndex(); + } + + if (voxel->isKnownBufferIndex() || (voxel->getPrimitiveIndex() != 0)) { const bool extraDebugging = false; // enable for extra debugging if (extraDebugging) { - qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s", + qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s, culledFaces=0x%02x \n", voxel->getCorner().x, voxel->getCorner().y, voxel->getCorner().z, voxel->getScale(), - nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender())); + nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender()), + voxel->getInteriorOcclusions()); } if (args->hasIndexFound[nodeIndex]) { @@ -2309,12 +2637,14 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { glBufferIndex minDirty = GLBUFFER_INDEX_UNKNOWN; glBufferIndex maxDirty = 0; - for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { - if (_writeVoxelDirtyArray[i]) { - minDirty = std::min(minDirty,i); - maxDirty = std::max(maxDirty,i); - } - } + if (!_usePrimitiveRenderer) { + for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { + if (_writeVoxelDirtyArray[i]) { + minDirty = std::min(minDirty,i); + maxDirty = std::max(maxDirty,i); + } + } + } collectStatsForTreesAndVBOsArgs args(_maxVoxels); args.expectedMax = _voxelsInWriteArrays; @@ -2323,7 +2653,7 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { _tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args); - qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld", + qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n", args.totalNodes, args.leafNodes, args.dirtyNodes, args.coloredNodes, args.shouldRenderNodes); qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld", debug::valueOf(_voxelsDirty), @@ -2332,6 +2662,9 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld", args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex, args.nodesInVBONotShouldRender); + qDebug(" inPrimitiveRenderer %ld \n completely culled %ld \n", + args.nodesInPrimitiveRenderer, args.culledLeafNodes); + glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN; glBufferIndex maxInVBO = 0; @@ -2775,5 +3108,102 @@ void VoxelSystem::beginLoadingLocalVoxelCache() { qDebug() << "DONE beginLoadingLocalVoxelCache()"; } +// Octant bitmask array indexed by octant. The mask value indicates the octant's halfspace partitioning. The index +// value corresponds to the voxel's octal code derived in "pointToVoxel" in SharedUtil.cpp, which, BTW, does *not* +// correspond to the "ChildIndex" enum value in OctreeElement.h +unsigned char VoxelSystem::octantIndexToBitMask[8] = { + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Far, + OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Far, + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Far, + OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Far, +}; +// Two dimensional array map indexed by octant row and column. The mask value +// indicates the two faces shared by the octants +unsigned char VoxelSystem::octantIndexToSharedBitMask[8][8] = { + { // Index 0: Bottom-Left-Near + 0, // Bottom-Left-Near + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Left-Far + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Left-Near + 0, // Top-Left-Far + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Right-Near + 0, // Bottom-Right-Far + 0, // Top-Right-Near + 0, // Top-Right-Far + }, + { // Index 1: Bottom-Left-Far + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Left-Near + 0, // Bottom-Left-Far + 0, // Top-Left-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Left-Far + 0, // Bottom-Right-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Right-Far + 0, // Top-Right-Near + 0, // Top-Right-Far + }, + { // Index 2: Top-Left-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Left-Near + 0, // Bottom-Left-Far + 0, // Top-Left-Near + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Left-Far + 0, // Bottom-Right-Near + 0, // Bottom-Right-Far + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Right-Near + 0, // Top-Right-Far + }, + { // Index 3: Top-Left-Far + 0, // Bottom-Left-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Left-Far + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Left-Near + 0, // Top-Left-Far + 0, // Bottom-Right-Near + 0, // Bottom-Right-Far + 0, // Top-Right-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Right-Far + }, + { // Index 4: Bottom-Right-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Left-Near + 0, // Bottom-Left-Far + 0, // Top-Left-Near + 0, // Top-Left-Far + 0, // Bottom-Right-Near + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Right-Far + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Right-Near + 0, // Top-Right-Far + }, + { // Index 5: Bottom-Right-Far + 0, // Bottom-Left-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Left-Far + 0, // Top-Left-Near + 0, // Top-Left-Far + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Right-Near + 0, // Bottom-Right-Far + 0, // Top-Right-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Right-Far + }, + { // Index 6: Top-Right-Near + 0, // Bottom-Left-Near + 0, // Bottom-Left-Far + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Left-Near + 0, // Top-Left-Far + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Right-Near + 0, // Bottom-Right-Far + 0, // Top-Right-Near + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Right-Far + }, + { // Index 7: Top-Right-Far + 0, // Bottom-Left-Near + 0, // Bottom-Left-Far + 0, // Top-Left-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Left-Far + 0, // Bottom-Right-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Right-Far + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Right-Near + 0, // Top-Right-Far + }, +}; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 728106a922..9dc89c3631 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -24,11 +24,13 @@ #include "Util.h" #include "world.h" #include "renderer/VoxelShader.h" +#include "PrimitiveRenderer.h" class ProgramObject; const int NUM_CHILDREN = 8; + struct VoxelShaderVBOData { float x, y, z; // position @@ -137,6 +139,7 @@ public slots: void falseColorizeBySource(); void forceRedrawEntireTree(); void clearAllNodesBufferIndex(); + void cullSharedFaces(); void cancelImport(); @@ -194,7 +197,10 @@ private: static bool killSourceVoxelsOperation(OctreeElement* element, void* extraData); static bool forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData); static bool clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData); - static bool hideOutOfViewOperation(OctreeElement* element, void* extraData); + static bool inspectForExteriorOcclusionsOperation(OctreeElement* element, void* extraData); + static bool inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData); + static bool clearOcclusionsOperation(OctreeElement* element, void* extraData); + static bool hideOutOfViewOperation(OctreeElement* element, void* extraData); static bool hideAllSubTreeOperation(OctreeElement* element, void* extraData); static bool showAllSubTreeOperation(OctreeElement* element, void* extraData); static bool showAllLocalVoxelsOperation(OctreeElement* element, void* extraData); @@ -308,6 +314,13 @@ private: void lockTree(); void unlockTree(); + + bool _usePrimitiveRenderer; + PrimitiveRenderer *_renderer; ///< Voxel renderer + + static unsigned char octantIndexToBitMask[8]; ///< Map octant index to partition mask + static unsigned char octantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask + }; #endif diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 5d25f0c164..7706148609 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -57,6 +57,11 @@ void Octree::recurseTreeWithOperation(RecurseOctreeOperation operation, void* ex recurseNodeWithOperation(_rootNode, operation, extraData); } +// Recurses voxel tree calling the RecurseOctreePostFixOperation function for each node in post-fix order. +void Octree::recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData) { + recurseNodeWithPostOperation(_rootNode, operation, extraData); +} + // Recurses voxel node with an operation function void Octree::recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData, int recursionCount) { @@ -75,6 +80,23 @@ void Octree::recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperatio } } +// Recurses voxel node with an operation function +void Octree::recurseNodeWithPostOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData, + int recursionCount) { + if (recursionCount > DANGEROUSLY_DEEP_RECURSION) { + qDebug() << "Octree::recurseNodeWithOperation() reached DANGEROUSLY_DEEP_RECURSION, bailing!\n"; + return; + } + + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + OctreeElement* child = node->getChildAtIndex(i); + if (child) { + recurseNodeWithPostOperation(child, operation, extraData, recursionCount+1); + } + } + operation(node, extraData); +} + // Recurses voxel tree calling the RecurseOctreeOperation function for each node. // stops recursion if operation function returns false. void Octree::recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation operation, diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 959c9272cf..f87dc086a8 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -210,6 +210,8 @@ public: void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData=NULL); + void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData=NULL); + void recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation operation, const glm::vec3& point, void* extraData=NULL); @@ -255,6 +257,11 @@ public: void recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData, int recursionCount = 0); + /** Traverse child nodes of node applying operation in post-fix order + */ + void recurseNodeWithPostOperation(OctreeElement* node, RecurseOctreeOperation operation, + void* extraData, int recursionCount = 0); + void recurseNodeWithOperationDistanceSorted(OctreeElement* node, RecurseOctreeOperation operation, const glm::vec3& point, void* extraData, int recursionCount = 0); diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 240bd10f98..77461f13bd 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -199,6 +199,19 @@ public: CHILD_UNKNOWN = -1 }; + struct HalfSpace { + enum { + Bottom = 0x01, + Top = 0x02, + Right = 0x04, + Left = 0x08, + Near = 0x10, + Far = 0x20, + All = 0x3f, + }; + }; + + OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); protected: diff --git a/libraries/voxels/src/VoxelTreeElement.cpp b/libraries/voxels/src/VoxelTreeElement.cpp index c98ed77b74..aff71584a8 100644 --- a/libraries/voxels/src/VoxelTreeElement.cpp +++ b/libraries/voxels/src/VoxelTreeElement.cpp @@ -13,7 +13,12 @@ #include "VoxelTreeElement.h" #include "VoxelTree.h" -VoxelTreeElement::VoxelTreeElement(unsigned char* octalCode) : OctreeElement() { +VoxelTreeElement::VoxelTreeElement(unsigned char* octalCode) : + OctreeElement(), + _primitiveIndex(0), + _exteriorOcclusions(0x3f), + _interiorOcclusions(0) +{ init(octalCode); }; diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h index 86732f4b66..5d32d49cec 100644 --- a/libraries/voxels/src/VoxelTreeElement.h +++ b/libraries/voxels/src/VoxelTreeElement.h @@ -49,6 +49,8 @@ public: + int getPrimitiveIndex() const { return _primitiveIndex; } + void setPrimitiveIndex(int index) { _primitiveIndex = index; } glBufferIndex getBufferIndex() const { return _glBufferIndex; } bool isKnownBufferIndex() const { return !_unknownBufferIndex; } void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; _unknownBufferIndex =(index == GLBUFFER_INDEX_UNKNOWN);} @@ -68,7 +70,12 @@ public: void setDensity(float density) { _density = density; } float getDensity() const { return _density; } - + + void setInteriorOcclusions(unsigned char interiorExclusions); + void setExteriorOcclusions(unsigned char exteriorOcclusions); + unsigned char getExteriorOcclusions() const; + unsigned char getInteriorOcclusions() const; + // type safe versions of OctreeElement methods VoxelTreeElement* getChildAtIndex(int childIndex) { return (VoxelTreeElement*)OctreeElement::getChildAtIndex(childIndex); } VoxelTreeElement* addChildAtIndex(int childIndex) { return (VoxelTreeElement*)OctreeElement::addChildAtIndex(childIndex); } @@ -89,7 +96,33 @@ protected: nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes + +private: + int _primitiveIndex; + unsigned char _exteriorOcclusions; ///< exterior shared partition boundaries that are completely occupied + unsigned char _interiorOcclusions; ///< interior shared partition boundaries with siblings }; +inline void VoxelTreeElement::setExteriorOcclusions(unsigned char exteriorOcclusions) { + if (_exteriorOcclusions != exteriorOcclusions) { + _exteriorOcclusions = exteriorOcclusions; + setDirtyBit(); + } +} -#endif /* defined(__hifi__VoxelTreeElement__) */ \ No newline at end of file +inline void VoxelTreeElement::setInteriorOcclusions(unsigned char interiorOcclusions) { + if (_interiorOcclusions != interiorOcclusions) { + _interiorOcclusions = interiorOcclusions; + setDirtyBit(); + } +} + +inline unsigned char VoxelTreeElement::getInteriorOcclusions() const { + return _interiorOcclusions; +} + +inline unsigned char VoxelTreeElement::getExteriorOcclusions() const { + return _exteriorOcclusions; +} + +#endif /* defined(__hifi__VoxelTreeElement__) */ From ef3d79593850c74e911bc57d207abf32996a67b1 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 4 Feb 2014 21:58:14 -0500 Subject: [PATCH 02/31] Fixes for style conformance --- interface/src/PrimitiveRenderer.cpp | 312 +++++++++++------------ interface/src/PrimitiveRenderer.h | 322 ++++++++++++------------ interface/src/VoxelSystem.cpp | 47 ++-- interface/src/VoxelSystem.h | 8 +- libraries/voxels/src/VoxelTreeElement.h | 4 +- 5 files changed, 324 insertions(+), 369 deletions(-) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index a285058a7c..fd1f3fd2e7 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -9,31 +9,27 @@ #include "OctreeElement.h" #include "PrimitiveRenderer.h" -Primitive::Primitive() -{} +Primitive::Primitive() { +} -Primitive::~Primitive() -{} +Primitive::~Primitive() { +} // Simple dispatch between API and SPI -VertexElementList const & Primitive::vertexElements() const -{ +VertexElementList const & Primitive::vertexElements() const { return vVertexElements(); } -VertexElementIndexList & Primitive::vertexElementIndices() -{ +VertexElementIndexList& Primitive::vertexElementIndices() { return vVertexElementIndices(); } -TriElementList & Primitive::triElements() -{ +TriElementList& Primitive::triElements() { return vTriElements(); } -void Primitive::releaseVertexElements() -{ +void Primitive::releaseVertexElements() { vReleaseVertexElements(); } @@ -47,13 +43,11 @@ Cube::Cube( unsigned char g, unsigned char b, unsigned char faceExclusions - ) -{ + ) { initialize(x, y, z, s, r, g, b, faceExclusions); } -Cube::~Cube() -{ +Cube::~Cube() { terminate(); } @@ -66,14 +60,14 @@ void Cube::initialize( unsigned char g, unsigned char b, unsigned char faceExclusions - ) -{ + ) { + initializeVertices(x, y, z, s, r, g, b, faceExclusions); initializeTris(faceExclusions); } -void Cube::terminate() -{ +void Cube::terminate() { + terminateTris(); terminateVertices(); } @@ -87,27 +81,25 @@ void Cube::initializeVertices( unsigned char g, unsigned char b, unsigned char faceExclusions - ) -{ - for (int i = 0; i < 24; i++) - { + ) { + + for (int i = 0; i < _sNumVerticesPerCube; i++) { // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. - if (~faceExclusions & s_faceIndexToHalfSpaceMask[i >> 2]) - //if (~0x00 & s_faceIndexToHalfSpaceMask[i >> 2]) - //if (faceExclusions & s_faceIndexToHalfSpaceMask[i >> 2]) - { - VertexElement *v = new VertexElement(); - if (v) - { + if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { + //if (~0x00 & _sFaceIndexToHalfSpaceMask[i >> 2]) { + //if (faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { + + VertexElement* v = new VertexElement(); + if (v) { // Construct vertex position - v->position.x = x + s * s_vertexIndexToConstructionVector[i][0]; - v->position.y = y + s * s_vertexIndexToConstructionVector[i][1]; - v->position.z = z + s * s_vertexIndexToConstructionVector[i][2]; + v->position.x = x + s * _sVertexIndexToConstructionVector[i][0]; + v->position.y = y + s * _sVertexIndexToConstructionVector[i][1]; + v->position.z = z + s * _sVertexIndexToConstructionVector[i][2]; // Construct vertex normal - v->normal.x = s_vertexIndexToNormalVector[i >> 2][0]; - v->normal.y = s_vertexIndexToNormalVector[i >> 2][1]; - v->normal.z = s_vertexIndexToNormalVector[i >> 2][2]; + v->normal.x = _sVertexIndexToNormalVector[i >> 2][0]; + v->normal.y = _sVertexIndexToNormalVector[i >> 2][1]; + v->normal.z = _sVertexIndexToNormalVector[i >> 2][2]; // Construct vertex color //#define FALSE_COLOR @@ -138,13 +130,12 @@ void Cube::initializeVertices( } } -void Cube::terminateVertices() -{ +void Cube::terminateVertices() { + VertexElementList::iterator it = _vertices.begin(); VertexElementList::iterator end = _vertices.end(); - for ( ; it != end; ++it) - { + for ( ; it != end; ++it) { delete *it; } _vertices.clear(); @@ -152,17 +143,16 @@ void Cube::terminateVertices() void Cube::initializeTris( unsigned char faceExclusions - ) -{ + ) { + int index = 0; - for (int i = 0; i < 6; i++) - { + for (int i = 0; i < _sNumFacesPerCube; i++) { // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. // uncomment this line to exclude shared faces: - if (~faceExclusions & s_faceIndexToHalfSpaceMask[i]) - // uncomment this line to load all faces: if (~0x00 & s_faceIndexToHalfSpaceMask[i]) - // uncomment this line to include shared faces: if (faceExclusions & s_faceIndexToHalfSpaceMask[i]) - { + if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { + // uncomment this line to load all faces: if (~0x00 & _sFaceIndexToHalfSpaceMask[i]) { + // uncomment this line to include shared faces: if (faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { + int start = index; // Create the triangulated face, two tris, six indices referencing four vertices, both // with cw winding order, such that: @@ -174,8 +164,7 @@ void Cube::initializeTris( // Store triangle ABC TriElement *tri = new TriElement(); - if (tri) - { + if (tri) { tri->indices[0] = index++; tri->indices[1] = index++; tri->indices[2] = index; @@ -186,8 +175,7 @@ void Cube::initializeTris( // Now store triangle ACD tri = new TriElement(); - if (tri) - { + if (tri) { tri->indices[0] = start; tri->indices[1] = index++; tri->indices[2] = index++; @@ -199,39 +187,34 @@ void Cube::initializeTris( } } -void Cube::terminateTris() -{ +void Cube::terminateTris() { + TriElementList::iterator it = _tris.begin(); TriElementList::iterator end = _tris.end(); - for ( ; it != end; ++it) - { + for ( ; it != end; ++it) { delete *it; } _tris.clear(); } -VertexElementList const & Cube::vVertexElements() const -{ +VertexElementList const & Cube::vVertexElements() const { return _vertices; } -VertexElementIndexList & Cube::vVertexElementIndices() -{ +VertexElementIndexList& Cube::vVertexElementIndices() { return _vertexIndices; } -TriElementList & Cube::vTriElements() -{ +TriElementList& Cube::vTriElements() { return _tris; } -void Cube::vReleaseVertexElements() -{ +void Cube::vReleaseVertexElements() { terminateVertices(); } -unsigned char Cube::s_faceIndexToHalfSpaceMask[6] = { +unsigned char Cube::_sFaceIndexToHalfSpaceMask[6] = { OctreeElement::HalfSpace::Bottom, OctreeElement::HalfSpace::Top, OctreeElement::HalfSpace::Right, @@ -244,7 +227,7 @@ unsigned char Cube::s_faceIndexToHalfSpaceMask[6] = { #ifdef CW_CONSTRUCTION // Construction vectors ordered such that the vertices of each face are // CW in a right-handed coordinate system with B-L-N at 0,0,0. -float Cube::s_vertexIndexToConstructionVector[24][3] = { +float Cube::_sVertexIndexToConstructionVector[24][3] = { // Bottom { 0,0,0 }, { 1,0,0 }, @@ -279,7 +262,7 @@ float Cube::s_vertexIndexToConstructionVector[24][3] = { #else // CW_CONSTRUCTION // Construction vectors ordered such that the vertices of each face are // CCW in a right-handed coordinate system with B-L-N at 0,0,0. -float Cube::s_vertexIndexToConstructionVector[24][3] = { +float Cube::_sVertexIndexToConstructionVector[24][3] = { // Bottom { 0,0,0 }, { 0,0,1 }, @@ -314,7 +297,7 @@ float Cube::s_vertexIndexToConstructionVector[24][3] = { #endif // Normals for a right-handed coordinate system -float Cube::s_vertexIndexToNormalVector[6][3] = { +float Cube::_sVertexIndexToNormalVector[6][3] = { { 0,-1, 0 }, // Bottom { 0, 1, 0 }, // Top { 1, 0, 0 }, // Right @@ -323,29 +306,26 @@ float Cube::s_vertexIndexToNormalVector[6][3] = { { 0, 0, 1 }, // Far }; -Renderer::Renderer() -{} +Renderer::Renderer() { +} -Renderer::~Renderer() -{} +Renderer::~Renderer() { +} // Simple dispatch between API and SPI int Renderer::add( - Primitive *primitive - ) -{ + Primitive* primitive + ) { return vAdd(primitive); } void Renderer::remove( int id - ) -{ + ) { vRemove(id); } -void Renderer::render() -{ +void Renderer::render() { vRender(); } @@ -369,19 +349,19 @@ PrimitiveRenderer::PrimitiveRenderer( initialize(); } -PrimitiveRenderer::~PrimitiveRenderer() -{ +PrimitiveRenderer::~PrimitiveRenderer() { + terminate(); } -void PrimitiveRenderer::initialize() -{ +void PrimitiveRenderer::initialize() { + initializeGL(); initializeBookkeeping(); } -void PrimitiveRenderer::initializeGL() -{ +void PrimitiveRenderer::initializeGL() { + glGenBuffers(1, &_triBufferId); glGenBuffers(1, &_vertexBufferId); @@ -417,51 +397,54 @@ void PrimitiveRenderer::initializeGL() GLint err = glGetError(); } -void PrimitiveRenderer::initializeBookkeeping() -{ +void PrimitiveRenderer::initializeBookkeeping() { + + // Start primitive count at one, because zero is reserved for the degenerate triangle _primitiveCount = 1; _cpuMemoryUsage = sizeof(PrimitiveRenderer); } -void PrimitiveRenderer::terminate() -{ +void PrimitiveRenderer::terminate() { + terminateBookkeeping(); terminateGL(); } -void PrimitiveRenderer::terminateGL() -{ +void PrimitiveRenderer::terminateGL() { + glDeleteBuffers(1, &_vertexBufferId); glDeleteBuffers(1, &_triBufferId); GLint err = glGetError(); } -void PrimitiveRenderer::terminateBookkeeping() -{ +void PrimitiveRenderer::terminateBookkeeping() { + // Drain all of the queues, stop updating the counters - while (_availableVertexElementIndex.remove()); - while (_availableTriElementIndex.remove()); - while (_deconstructTriElementIndex.remove()); + while (_availableVertexElementIndex.remove() != 0) + ; + + while (_availableTriElementIndex.remove() != 0) + ; + + while (_deconstructTriElementIndex.remove() != 0) + ; std::map::iterator it = _indexToPrimitiveMap.begin(); std::map::iterator end = _indexToPrimitiveMap.end(); - for ( ; it != end; ++it) - { + for ( ; it != end; ++it) { Primitive *primitive = it->second; delete primitive; } } int PrimitiveRenderer::vAdd( - Primitive *primitive - ) -{ + Primitive* primitive + ) { + int index = getAvailablePrimitiveIndex(); - if (index != 0) - { - try - { + if (index != 0) { + try { // Take ownership of primitive, including responsibility // for destruction _indexToPrimitiveMap[index] = primitive; @@ -469,9 +452,7 @@ int PrimitiveRenderer::vAdd( // No need to keep an extra copy of the vertices primitive->releaseVertexElements(); - } - catch(...) - { + } catch(...) { // STL failed, recycle the index _availablePrimitiveIndex.add(index); index = 0; @@ -482,17 +463,15 @@ int PrimitiveRenderer::vAdd( void PrimitiveRenderer::vRemove( int index - ) -{ - try - { + ) { + + try { + // Locate the primitive by id in the associative map std::map::iterator it = _indexToPrimitiveMap.find(index); - if (it != _indexToPrimitiveMap.end()) - { + if (it != _indexToPrimitiveMap.end()) { Primitive *primitive = it->second; - if (primitive) - { + if (primitive) { _indexToPrimitiveMap[index] = 0; deconstructElements(primitive); _availablePrimitiveIndex.add(index); @@ -501,31 +480,27 @@ void PrimitiveRenderer::vRemove( // the index is going to be re-used, but if you want to... uncomment the following: //_indexToPrimitiveMap.erase(it); } - } - catch(...) - { + } catch(...) { // STL failed } } void PrimitiveRenderer::constructElements( - Primitive *primitive - ) -{ + Primitive* primitive + ) { + // Load vertex elements - VertexElementIndexList & vertexElementIndexList = primitive->vertexElementIndices(); + VertexElementIndexList& vertexElementIndexList = primitive->vertexElementIndices(); { VertexElementList const & vertices = primitive->vertexElements(); VertexElementList::const_iterator it = vertices.begin(); VertexElementList::const_iterator end = vertices.end(); - for ( ; it != end; ++it ) - { + for ( ; it != end; ++it ) { int index = getAvailableVertexElementIndex(); - if (index != 0) - { + if (index != 0) { vertexElementIndexList.push_back(index); - VertexElement *vertex = *it; + VertexElement* vertex = *it; transferVertexElement(index, vertex); } } @@ -533,16 +508,14 @@ void PrimitiveRenderer::constructElements( // Load tri elements { - TriElementList & tris = primitive->triElements(); + TriElementList& tris = primitive->triElements(); TriElementList::iterator it = tris.begin(); TriElementList::iterator end = tris.end(); - for ( ; it != end; ++it) - { - TriElement *tri = *it; + for ( ; it != end; ++it) { + TriElement* tri = *it; int index = getAvailableTriElementIndex(); - if (index != 0) - { + if (index != 0) { int k; k = tri->indices[0]; tri->indices[0] = vertexElementIndexList[k]; @@ -561,18 +534,17 @@ void PrimitiveRenderer::constructElements( } void PrimitiveRenderer::deconstructElements( - Primitive *primitive - ) -{ + Primitive* primitive + ) { + // Schedule the tri elements of the face for deconstruction { - TriElementList & tris = primitive->triElements(); + TriElementList& tris = primitive->triElements(); TriElementList::iterator it = tris.begin(); TriElementList::iterator end = tris.end(); - for ( ; it != end; ++it) - { - TriElement *tri = *it; + for ( ; it != end; ++it) { + TriElement* tri = *it; // Put the tri element index into decon queue _deconstructTriElementIndex.add(tri->id); @@ -581,12 +553,11 @@ void PrimitiveRenderer::deconstructElements( // Return the vertex element index to the available queue, it is not necessary // to zero the data { - VertexElementIndexList & vertexIndexList = primitive->vertexElementIndices(); + VertexElementIndexList& vertexIndexList = primitive->vertexElementIndices(); VertexElementIndexList::iterator it = vertexIndexList.begin(); VertexElementIndexList::iterator end = vertexIndexList.end(); - for ( ; it != end; ++it) - { + for ( ; it != end; ++it) { int index = *it; // Put the vertex element index into the available queue @@ -598,13 +569,12 @@ void PrimitiveRenderer::deconstructElements( delete primitive; } -int PrimitiveRenderer::getAvailablePrimitiveIndex() -{ +int PrimitiveRenderer::getAvailablePrimitiveIndex() { + // Check the available primitive index queue first for an available index. int index = _availablePrimitiveIndex.remove(); // Remember that the primitive index 0 is used not used. - if (index == 0) - { + if (index == 0) { // There are no primitive indices available from the queue, // make one up index = _primitiveCount++; @@ -612,37 +582,36 @@ int PrimitiveRenderer::getAvailablePrimitiveIndex() return index; } -int PrimitiveRenderer::getAvailableVertexElementIndex() -{ +int PrimitiveRenderer::getAvailableVertexElementIndex() { + // Check the available vertex element queue first for an available index. int index = _availableVertexElementIndex.remove(); // Remember that the vertex element 0 is used for degenerate triangles. - if (index == 0) - { + if (index == 0) { // There are no vertex elements available from the queue, // grab one from the end of the list - if (_vertexElementCount < _maxVertexElementCount) + if (_vertexElementCount < _maxVertexElementCount) { index = _vertexElementCount++; + } } return index; } -int PrimitiveRenderer::getAvailableTriElementIndex() -{ +int PrimitiveRenderer::getAvailableTriElementIndex() { + // Check the deconstruct tri element queue first for an available index. int index = _deconstructTriElementIndex.remove(); // Remember that the tri element 0 is used for degenerate triangles. - if (index == 0) - { + if (index == 0) { // There are no tri elements in the deconstruct tri element queue that are reusable. // Check the available tri element queue. index = _availableTriElementIndex.remove(); - if (index == 0) - { + if (index == 0) { // There are no reusable tri elements available from any queue, // grab one from the end of the list - if (_triElementCount < _maxTriElementCount) + if (_triElementCount < _maxTriElementCount) { index = _triElementCount++; + } } } return index; @@ -650,8 +619,8 @@ int PrimitiveRenderer::getAvailableTriElementIndex() void PrimitiveRenderer::deconstructTriElement( int idx - ) -{ + ) { + // Set the element to the degenerate case. int degenerate[3] = { 0, 0, 0 }; transferTriElement(idx, degenerate); @@ -660,9 +629,9 @@ void PrimitiveRenderer::deconstructTriElement( void PrimitiveRenderer::transferVertexElement( int idx, - VertexElement *vertex - ) -{ + VertexElement* vertex + ) { + glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); glBufferSubData(GL_ARRAY_BUFFER, idx * sizeof(VertexElement), sizeof(VertexElement), vertex); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -671,20 +640,19 @@ void PrimitiveRenderer::transferVertexElement( void PrimitiveRenderer::transferTriElement( int idx, int tri[3] -) -{ + ) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, idx * sizeof(GLint) * 3, sizeof(GLint) * 3, tri); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } -void PrimitiveRenderer::vRender() -{ +void PrimitiveRenderer::vRender() { + // Now would be an appropriate time to set the element array buffer ids // scheduled for deconstruction to the degenerate case. int id; - while ((id = _deconstructTriElementIndex.remove())) - { + while ((id = _deconstructTriElementIndex.remove()) != 0) { deconstructTriElement(id); _availableTriElementIndex.add(id); } diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/PrimitiveRenderer.h index e54842c229..24fee66184 100644 --- a/interface/src/PrimitiveRenderer.h +++ b/interface/src/PrimitiveRenderer.h @@ -1,24 +1,23 @@ -/** - * @file PrimitiveRenderer.h - * A geometric primitive renderer. - * - * @author: Norman Crafts - * @copyright 2014, High Fidelity, Inc. All rights reserved. - */ +/// +/// @file PrimitiveRenderer.h +/// A geometric primitive renderer. +/// +/// @author: Norman Crafts +/// @copyright 2014, High Fidelity, Inc. All rights reserved. +/// #ifndef __interface__PrimitiveRenderer__ #define __interface__PrimitiveRenderer__ #include -#include +#include "Queue.h" -/** Vertex element structure - * Using the array of structures approach to specifying - * vertex data to GL cuts down on the calls to glBufferSubData - */ +/// Vertex element structure. +/// Using the array of structures approach to specifying +/// vertex data to GL cuts down on the calls to glBufferSubData +/// typedef - struct __VertexElement - { + struct __VertexElement { struct __position { float x; float y; @@ -37,102 +36,98 @@ typedef } color; } VertexElement; -/** Triangle element index structure - * Specify the vertex indices of the triangle and its element index. - */ -typedef -struct __TriElement -{ - int indices[3]; - int id; +/// Triangle element index structure. +/// Specify the vertex indices of the triangle and its element index. +/// +typedef + struct __TriElement { + int indices[3]; + int id; -} TriElement; + } TriElement; typedef std::vector > VertexElementList; typedef std::vector > VertexElementIndexList; typedef std::vector > TriElementList; -/** - * @class Primitive - * Primitive Interface class - * Abstract class for accessing vertex and tri elements of geometric primitives - * - */ -class Primitive -{ +/// +/// @class Primitive +/// Primitive Interface class. +/// Abstract class for accessing vertex and tri elements of geometric primitives +/// +/// +class Primitive { public: virtual ~Primitive(); // API methods go here - /** Vertex element accessor - * @return A list of vertex elements of the primitive - */ + /// Vertex element accessor. + /// @return A list of vertex elements of the primitive + /// VertexElementList const & vertexElements() const; - /** Vertex element index accessor - * @return A list of vertex element indices of the primitive - */ - VertexElementIndexList & vertexElementIndices(); + /// Vertex element index accessor. + /// @return A list of vertex element indices of the primitive + /// + VertexElementIndexList& vertexElementIndices(); - /** Tri element accessor - * @return A list of tri elements of the primitive - */ - TriElementList & triElements(); + /// Tri element accessor. + /// @return A list of tri elements of the primitive + /// + TriElementList& triElements(); - /** Release vertex elements - */ + /// Release vertex elements. + /// void releaseVertexElements(); protected: - /** Default constructor prohibited to API user, restricted to service implementer - */ + /// Default constructor prohibited to API user, restricted to service implementer. + /// Primitive(); private: - /** Copy constructor prohibited - */ + /// Copy constructor prohibited. + /// Primitive( Primitive const & prim ); // SPI methods are defined here - /** Vertex element accessor - * Service implementer to provide private override for this method - * in derived class - */ + /// Vertex element accessor. + /// Service implementer to provide private override for this method + /// in derived class + /// virtual VertexElementList const & vVertexElements() const = 0; - /** Vertex element index accessor - * Service implementer to provide private override for this method - * in derived class - */ - virtual VertexElementIndexList & vVertexElementIndices() = 0; + /// Vertex element index accessor. + /// Service implementer to provide private override for this method + /// in derived class + /// + virtual VertexElementIndexList& vVertexElementIndices() = 0; - /** Tri element accessor - * Service implementer to provide private override for this method - * in derived class - */ - virtual TriElementList & vTriElements() = 0; + /// Tri element accessor. + /// Service implementer to provide private override for this method + /// in derived class + /// + virtual TriElementList& vTriElements() = 0; - /** Release vertex elements - */ + /// Release vertex elements. + /// virtual void vReleaseVertexElements() = 0; }; -/** - * @class Cube - * Class for accessing the vertex and tri elements of a cube - */ -class Cube: - public Primitive -{ +/// +/// @class Cube +/// Class for accessing the vertex and tri elements of a cube +/// +class Cube: public Primitive { public: - /** Configuration dependency injection constructor - */ + /// Configuration dependency injection constructor. + /// Cube( float x, float y, @@ -147,8 +142,8 @@ public: ~Cube(); private: - /** Copy constructor prohibited - */ + /// Copy constructor prohibited. + /// Cube ( Cube const & cube ); @@ -188,8 +183,8 @@ private: // SPI virtual override methods go here VertexElementList const & vVertexElements() const; - VertexElementIndexList & vVertexElementIndices(); - TriElementList & vTriElements(); + VertexElementIndexList& vVertexElementIndices(); + TriElementList& vTriElements(); void vReleaseVertexElements(); @@ -198,91 +193,90 @@ private: VertexElementIndexList _vertexIndices; ///< Vertex element index list TriElementList _tris; ///< Tri element list - static unsigned char s_faceIndexToHalfSpaceMask[6]; - static float s_vertexIndexToConstructionVector[24][3]; - static float s_vertexIndexToNormalVector[6][3]; + static const int _sNumFacesPerCube = 6; + static const int _sNumVerticesPerCube = 24; + static unsigned char _sFaceIndexToHalfSpaceMask[6]; + static float _sVertexIndexToConstructionVector[24][3]; + static float _sVertexIndexToNormalVector[6][3]; }; -/** - * @class Renderer - * GL renderer interface class - * Abstract class for rendering geometric primitives in GL - */ -class Renderer -{ +/// +/// @class Renderer +/// GL renderer interface class. +/// Abstract class for rendering geometric primitives in GL +/// +class Renderer { public: virtual ~Renderer(); // API methods go here - /** Add primitive to renderer database - */ + /// Add primitive to renderer database. + /// int add( - Primitive *primitive ///< Pointer to primitive + Primitive* primitive ///< Pointer to primitive ); - /** Remove primitive from renderer database - */ + /// Remove primitive from renderer database. + /// void remove( int id ///< Primitive id ); - /** Render primitive database - * The render method assumes appropriate GL context and state has - * already been provided for - */ + /// Render primitive database. + /// The render method assumes appropriate GL context and state has + /// already been provided for + /// void render(); protected: - /** Default constructor prohibited to API user, restricted to service implementer - */ + /// Default constructor prohibited to API user, restricted to service implementer. + /// Renderer(); private: - /** Copy constructor prohibited - */ + /// Copy constructor prohibited. + /// Renderer( Renderer const & primitive ); // SPI methods are defined here - /** Add primitive to renderer database - * Service implementer to provide private override for this method - * in derived class - */ + /// Add primitive to renderer database. + /// Service implementer to provide private override for this method + /// in derived class + /// virtual int vAdd( - Primitive *primitive ///< Pointer to primitive + Primitive* primitive ///< Pointer to primitive ) = 0; - /** Remove primitive from renderer database - * Service implementer to provide private override for this method - * in derived class - */ + /// Remove primitive from renderer database. + /// Service implementer to provide private override for this method + /// in derived class + /// virtual void vRemove( int id ///< Primitive id ) = 0; - /** Render primitive database - * Service implementer to provide private virtual override for this method - * in derived class - */ + /// Render primitive database. + /// Service implementer to provide private virtual override for this method + /// in derived class + /// virtual void vRender() = 0; }; -/** - * @class PrimitiveRenderer - * Renderer implementation class for the rendering of geometric primitives - * using GL element array and GL array buffers - */ -class PrimitiveRenderer : - public Renderer -{ +/// +/// @class PrimitiveRenderer +/// Renderer implementation class for the rendering of geometric primitives +/// using GL element array and GL array buffers +/// +class PrimitiveRenderer : public Renderer { public: - /** Configuration dependency injection constructor - */ + /// Configuration dependency injection constructor. + /// PrimitiveRenderer( int maxCount ); @@ -290,12 +284,12 @@ public: ~PrimitiveRenderer(); private: - /** Default constructor prohibited - */ + /// Default constructor prohibited. + /// PrimitiveRenderer(); - /** Copy constructor prohibited - */ + /// Copy constructor prohibited. + /// PrimitiveRenderer( PrimitiveRenderer const & renderer ); @@ -303,84 +297,84 @@ private: void initialize(); void terminate(); - /** Allocate and initialize GL buffers - */ + /// Allocate and initialize GL buffers. + /// void initializeGL(); - /** Terminate and deallocate GL buffers - */ + /// Terminate and deallocate GL buffers. + /// void terminateGL(); void initializeBookkeeping(); void terminateBookkeeping(); - /** Construct the elements of the faces of the primitive - */ + /// Construct the elements of the faces of the primitive. + /// void constructElements( - Primitive *primitive + Primitive* primitive ); - /** Deconstruct the elements of the faces of the primitive - */ + /// Deconstruct the elements of the faces of the primitive. + /// void deconstructElements( - Primitive *primitive + Primitive* primitive ); - /** Deconstruct the triangle element from the GL buffer - */ + /// Deconstruct the triangle element from the GL buffer. + /// void deconstructTriElement( int idx ); - /** Transfer the vertex element to the GL buffer - */ + /// Transfer the vertex element to the GL buffer. + /// void transferVertexElement( int idx, VertexElement *vertex ); - /** Transfer the triangle element to the GL buffer - */ + /// Transfer the triangle element to the GL buffer. + /// void transferTriElement( int idx, int tri[3] ); - /** Get available primitive index - * Get an available primitive index from either the recycling - * queue or incrementing the counter - */ + /// Get available primitive index. + /// Get an available primitive index from either the recycling + /// queue or incrementing the counter + /// int getAvailablePrimitiveIndex(); - /** Get available vertex element index - * Get an available vertex element index from either the recycling - * queue or incrementing the counter - */ + /// Get available vertex element index. + /// Get an available vertex element index from either the recycling + /// queue or incrementing the counter + /// int getAvailableVertexElementIndex(); - /** Get available triangle element index - * Get an available triangle element index from either the elements - * scheduled for deconstruction queue, the recycling - * queue or incrementing the counter - */ + /// Get available triangle element index. + /// Get an available triangle element index from either the elements + /// scheduled for deconstruction queue, the recycling + /// queue or incrementing the counter + /// int getAvailableTriElementIndex(); // SPI virtual override methods go here - /** Add primitive to renderer database - */ + /// Add primitive to renderer database. + /// int vAdd( - Primitive *primitive + Primitive* primitive ); - /** Remove primitive from renderer database - */ + /// Remove primitive from renderer database. + /// void vRemove( int id ); - /** Render triangle database - */ + /// Render triangle database. + /// void vRender(); private: @@ -400,7 +394,7 @@ private: int _triElementCount; ///< Count of triangles int _maxTriElementCount; ///< Max count of triangles - std::map _indexToPrimitiveMap; ///< Associative map between index and primitive + std::map _indexToPrimitiveMap; ///< Associative map between index and primitive int _primitiveCount; ///< Count of primitives Queue _availablePrimitiveIndex; ///< Queue of primitive indices available diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 454f82f6b6..d128627b42 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1050,15 +1050,13 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo if (primitiveIndex) { _renderer->remove(primitiveIndex); node->setPrimitiveIndex(0); - } - else { + } else { node->setVoxelSystem(this); } inspectForInteriorOcclusionsOperation(node, 0); - if (node->getInteriorOcclusions() != OctreeElement::HalfSpace::All) - { - Cube *cube = new Cube( + if (node->getInteriorOcclusions() != OctreeElement::HalfSpace::All) { + Cube* cube = new Cube( startVertex.x, startVertex.y, startVertex.z, voxelScale, color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX], node->getInteriorOcclusions()); @@ -1067,8 +1065,7 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo node->setPrimitiveIndex(primitiveIndex); } } - } - else { + } else { glBufferIndex nodeIndex = GLBUFFER_INDEX_UNKNOWN; if (reuseIndex && node->isKnownBufferIndex()) { nodeIndex = node->getBufferIndex(); @@ -1531,12 +1528,12 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, } // Bit mask of occluded shared faces indexed by child - unsigned char occludedSharedFace[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + unsigned char occludedSharedFace[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // Traverse all pair combinations of children for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { - VoxelTreeElement *childA = voxel->getChildAtIndex(i); + VoxelTreeElement* childA = voxel->getChildAtIndex(i); if (childA) { // Get the child A's occluding faces, for a leaf that will be @@ -1551,7 +1548,7 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, for (int j = i; --j >= 0; ) { - VoxelTreeElement *childB = voxel->getChildAtIndex(j); + VoxelTreeElement* childB = voxel->getChildAtIndex(j); if (childB) { // Get child B's occluding faces @@ -1564,22 +1561,22 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, // Determine the shared halfspace partition between siblings A and B, // i.e., near/far, left/right, or top/bottom - unsigned char partition = octantIndexToSharedBitMask[i][j] & + unsigned char partition = _sOctantIndexToSharedBitMask[i][j] & exteriorOcclusionsA & exteriorOcclusionsB; - // Determine which face of each sibling is occluded. + // Determine which face of each sibling is occluded. // Note the intentionally crossed indicies. It is necessary because - // the octantIndexToBitMask is a partition occupancy mask. For + // the _sOctantIndexToBitMask is a partition occupancy mask. For // example, if the near-left-top (NLT) and near-left-bottom (NLB) child voxels // exist, the shared partition is top-bottom (TB), and thus the occluded // shared face of the NLT voxel is its bottom face. - occludedSharedFace[i] |= (partition & octantIndexToBitMask[j]); - occludedSharedFace[j] |= (partition & octantIndexToBitMask[i]); + occludedSharedFace[i] |= (partition & _sOctantIndexToBitMask[j]); + occludedSharedFace[j] |= (partition & _sOctantIndexToBitMask[i]); } } // Combine this voxel's interior excluded shared face only to those children which are coincident // with the excluded face. - occludedSharedFace[i] |= (voxel->getInteriorOcclusions() & octantIndexToBitMask[i]); + occludedSharedFace[i] |= (voxel->getInteriorOcclusions() & _sOctantIndexToBitMask[i]); // Inform the child childA->setInteriorOcclusions(occludedSharedFace[i]); @@ -1610,13 +1607,13 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, // Traverse all children for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { - VoxelTreeElement *child = voxel->getChildAtIndex(i); + VoxelTreeElement* child = voxel->getChildAtIndex(i); if (child) { // Get the child's occluding faces, for a leaf, that will be // all six voxel faces, and for a non leaf, that will be // all faces which are completely covered by four child octants. unsigned char exteriorOcclusionsOfChild = child->getExteriorOcclusions(); - exteriorOcclusionsOfChild &= octantIndexToBitMask[i]; + exteriorOcclusionsOfChild &= _sOctantIndexToBitMask[i]; for (int j = 6; --j >= 0; ) { @@ -1656,9 +1653,7 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, // occupied. Hence, the subtree from this node could be // pruned and replaced by a leaf voxel, if the visible // properties of the children are the same - } - else - if (exteriorOcclusions) { + } else if (exteriorOcclusions) { //const glm::vec3& v = voxel->getCorner(); //float s = voxel->getScale(); @@ -1682,8 +1677,7 @@ bool VoxelSystem::clearOcclusionsOperation(OctreeElement* element, void* extraDa // And the sibling occluders voxel->setInteriorOcclusions(0); rc = false; - } - else { + } else { voxel->setExteriorOcclusions(0); voxel->setInteriorOcclusions(0); rc = true; @@ -1711,8 +1705,7 @@ void VoxelSystem::cullSharedFaces() { _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); unlockTree(); qDebug("culling shared faces in %d nodes", _nodeCount); - } - else { + } else { cleanupVoxelMemory(); _usePrimitiveRenderer = false; initVoxelMemory(); @@ -3112,7 +3105,7 @@ void VoxelSystem::beginLoadingLocalVoxelCache() { // Octant bitmask array indexed by octant. The mask value indicates the octant's halfspace partitioning. The index // value corresponds to the voxel's octal code derived in "pointToVoxel" in SharedUtil.cpp, which, BTW, does *not* // correspond to the "ChildIndex" enum value in OctreeElement.h -unsigned char VoxelSystem::octantIndexToBitMask[8] = { +unsigned char VoxelSystem::_sOctantIndexToBitMask[8] = { OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Far, OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, @@ -3125,7 +3118,7 @@ unsigned char VoxelSystem::octantIndexToBitMask[8] = { // Two dimensional array map indexed by octant row and column. The mask value // indicates the two faces shared by the octants -unsigned char VoxelSystem::octantIndexToSharedBitMask[8][8] = { +unsigned char VoxelSystem::_sOctantIndexToSharedBitMask[8][8] = { { // Index 0: Bottom-Left-Near 0, // Bottom-Left-Near OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Left-Far diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index da92b8921e..ee8c28178e 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -315,11 +315,11 @@ private: void lockTree(); void unlockTree(); - bool _usePrimitiveRenderer; - PrimitiveRenderer *_renderer; ///< Voxel renderer + bool _usePrimitiveRenderer; ///< Flag primitive renderer for use + PrimitiveRenderer* _renderer; ///< Voxel renderer - static unsigned char octantIndexToBitMask[8]; ///< Map octant index to partition mask - static unsigned char octantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask + static unsigned char _sOctantIndexToBitMask[8]; ///< Map octant index to partition mask + static unsigned char _sOctantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask }; diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h index 208148fa7d..a3c112fcde 100644 --- a/libraries/voxels/src/VoxelTreeElement.h +++ b/libraries/voxels/src/VoxelTreeElement.h @@ -99,8 +99,8 @@ protected: private: int _primitiveIndex; - unsigned char _exteriorOcclusions; ///< exterior shared partition boundaries that are completely occupied - unsigned char _interiorOcclusions; ///< interior shared partition boundaries with siblings + unsigned char _exteriorOcclusions; /// exterior shared partition boundaries that are completely occupied + unsigned char _interiorOcclusions; /// interior shared partition boundaries with siblings }; inline void VoxelTreeElement::setExteriorOcclusions(unsigned char exteriorOcclusions) { From 831a4a4e846ede1ae5019323e35bcecd183233a0 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 4 Feb 2014 22:58:05 -0500 Subject: [PATCH 03/31] Fixes for style conformance: tabs to spaces --- interface/src/AutoLock.h | 78 +-- interface/src/Mutex.h | 126 ++-- interface/src/PrimitiveRenderer.cpp | 908 ++++++++++++++-------------- interface/src/PrimitiveRenderer.h | 570 ++++++++--------- interface/src/Queue.h | 384 ++++++------ interface/src/Threading.h | 32 +- 6 files changed, 1049 insertions(+), 1049 deletions(-) diff --git a/interface/src/AutoLock.h b/interface/src/AutoLock.h index 875fbd5954..65746f85b5 100644 --- a/interface/src/AutoLock.h +++ b/interface/src/AutoLock.h @@ -1,10 +1,10 @@ /** - * @file AutoLock.h - * A simple locking class featuring templated mutex policy and mutex barrier - * activation/deactivation constructor/destructor. + * @file AutoLock.h + * A simple locking class featuring templated mutex policy and mutex barrier + * activation/deactivation constructor/destructor. * - * @author Norman Crafts - * @copyright 2014, All rights reserved. + * @author Norman Crafts + * @copyright 2014, All rights reserved. */ #ifndef __AUTOLOCK_H__ #define __AUTOLOCK_H__ @@ -12,73 +12,73 @@ #include "Mutex.h" /** - * @class AutoLock + * @class AutoLock */ template < - class MutexPolicy = Mutex + class MutexPolicy = Mutex > class AutoLock { public: - /** Dependency injection constructor - * AutoLock constructor with client mutex injection - */ - AutoLock( - MutexPolicy & client ///< Client mutex - ); + /** Dependency injection constructor + * AutoLock constructor with client mutex injection + */ + AutoLock( + MutexPolicy & client ///< Client mutex + ); - /** Dependency injection constructor - * AutoLock constructor with client mutex injection - */ - AutoLock( - MutexPolicy *client ///< Client mutex - ); + /** Dependency injection constructor + * AutoLock constructor with client mutex injection + */ + AutoLock( + MutexPolicy *client ///< Client mutex + ); - ~AutoLock(); + ~AutoLock(); private: - /** Default constructor prohibited to API user - */ - AutoLock(); + /** Default constructor prohibited to API user + */ + AutoLock(); - /** Copy constructor prohibited to API user - */ - AutoLock( - AutoLock const & copy - ); + /** Copy constructor prohibited to API user + */ + AutoLock( + AutoLock const & copy + ); private: - MutexPolicy &_mutex; ///< Client mutex + MutexPolicy &_mutex; ///< Client mutex }; template inline AutoLock::AutoLock( - MutexPolicy &mutex - ) : - _mutex(mutex) + MutexPolicy &mutex + ) : + _mutex(mutex) { - _mutex.lock(); + _mutex.lock(); } template inline AutoLock::AutoLock( - MutexPolicy *mutex - ) : - _mutex(*mutex) + MutexPolicy *mutex + ) : + _mutex(*mutex) { - _mutex.lock(); + _mutex.lock(); } template inline AutoLock::~AutoLock() { - _mutex.unlock(); + _mutex.unlock(); } -#endif // __AUTOLOCK_H__ +#endif // __AUTOLOCK_H__ diff --git a/interface/src/Mutex.h b/interface/src/Mutex.h index 4fd7ecf9ab..e08cf4407f 100644 --- a/interface/src/Mutex.h +++ b/interface/src/Mutex.h @@ -1,9 +1,9 @@ /** - * @file Mutex.h - * An operating system independent simple wrapper to mutex services. + * @file Mutex.h + * An operating system independent simple wrapper to mutex services. * - * @author: Norman Crafts - * @copyright 2014, All rights reserved. + * @author: Norman Crafts + * @copyright 2014, All rights reserved. */ #ifndef __MUTEX_H__ #define __MUTEX_H__ @@ -14,52 +14,52 @@ #endif /** - * @class Mutex + * @class Mutex * - * This class is an OS independent delegate pattern providing access - * to simple OS dependent mutex services. Assume the mutex service is - * non-reentrant. + * This class is an OS independent delegate pattern providing access + * to simple OS dependent mutex services. Assume the mutex service is + * non-reentrant. */ class Mutex { public: - /** Default constructor - */ - Mutex(); + /** Default constructor + */ + Mutex(); - ~Mutex(); + ~Mutex(); - /** Lock the mutex barrier - * First competing thread will capture the mutex and block all - * other threads. - */ - void lock(); + /** Lock the mutex barrier + * First competing thread will capture the mutex and block all + * other threads. + */ + void lock(); - /** Unlock the mutex barrier - * Mutex owner releases the mutex and allow competing threads to try to capture. - */ - void unlock(); + /** Unlock the mutex barrier + * Mutex owner releases the mutex and allow competing threads to try to capture. + */ + void unlock(); private: - /** Copy constructor prohibited to API user - */ - Mutex( - Mutex const & copy - ); + /** Copy constructor prohibited to API user + */ + Mutex( + Mutex const & copy + ); private: #ifdef _DEBUG - int _lockCt; -#endif //_DEBUG + int _lockCt; +#endif //_DEBUG #ifdef WIN32 - CRITICAL_SECTION _mutex; -#endif // WIN32 + CRITICAL_SECTION _mutex; +#endif // WIN32 #ifdef LINUX - pthread_mutex_t _mutex; -#endif // LINUX + pthread_mutex_t _mutex; +#endif // LINUX }; @@ -68,79 +68,79 @@ private: inline Mutex::Mutex() #ifdef _DEBUG - : - _lockCt(0) + : + _lockCt(0) #endif { - InitializeCriticalSection(&_mutex); + InitializeCriticalSection(&_mutex); } inline Mutex::~Mutex() { - DeleteCriticalSection(&_mutex); + DeleteCriticalSection(&_mutex); } inline void Mutex::lock() { - EnterCriticalSection(&_mutex); - #ifdef _DEBUG - _lockCt++; - #endif // _DEBUG + EnterCriticalSection(&_mutex); + #ifdef _DEBUG + _lockCt++; + #endif // _DEBUG } inline void Mutex::unlock() { - #ifdef _DEBUG - _lockCt--; - #endif // _DEBUG - LeaveCriticalSection(&_mutex); + #ifdef _DEBUG + _lockCt--; + #endif // _DEBUG + LeaveCriticalSection(&_mutex); } -#endif // WIN32 +#endif // WIN32 #ifdef LINUX inline Mutex::Mutex() #ifdef _DEBUG - : - _lockCt(0) + : + _lockCt(0) #endif { - int err; - pthread_mutexattr_t attrib; + int err; + pthread_mutexattr_t attrib; - err = pthread_mutexattr_init(&attrib); - err = pthread_mutex_init(&_mutex, &attrib); - err = pthread_mutexattr_destroy(&attrib); + err = pthread_mutexattr_init(&attrib); + err = pthread_mutex_init(&_mutex, &attrib); + err = pthread_mutexattr_destroy(&attrib); } inline Mutex::~Mutex() { - pthread_mutex_destroy(&_mutex); + pthread_mutex_destroy(&_mutex); } inline void Mutex::lock() { - pthread_mutex_lock(&_mutex); - #ifdef _DEBUG - _lockCt++; - #endif // _DEBUG + pthread_mutex_lock(&_mutex); + #ifdef _DEBUG + _lockCt++; + #endif // _DEBUG } inline void Mutex::unlock() { - #ifdef _DEBUG - _lockCt--; - #endif // _DEBUG - pthread_mutex_unlock(&_mutex); + #ifdef _DEBUG + _lockCt--; + #endif // _DEBUG + pthread_mutex_unlock(&_mutex); } -#endif // LINUX -#endif // __MUTEX_H__ +#endif // LINUX +#endif // __MUTEX_H__ diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index fd1f3fd2e7..05c0c9444a 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -1,9 +1,9 @@ /** - * @file PrimitiveRenderer.cpp - * A geometric primitive renderer. + * @file PrimitiveRenderer.cpp + * A geometric primitive renderer. * - * @author: Norman Crafts - * @copyright 2014, High Fidelity, Inc. All rights reserved. + * @author: Norman Crafts + * @copyright 2014, High Fidelity, Inc. All rights reserved. */ #include "InterfaceConfig.h" #include "OctreeElement.h" @@ -18,209 +18,209 @@ Primitive::~Primitive() { // Simple dispatch between API and SPI VertexElementList const & Primitive::vertexElements() const { - return vVertexElements(); + return vVertexElements(); } VertexElementIndexList& Primitive::vertexElementIndices() { - return vVertexElementIndices(); + return vVertexElementIndices(); } TriElementList& Primitive::triElements() { - return vTriElements(); + return vTriElements(); } void Primitive::releaseVertexElements() { - vReleaseVertexElements(); + vReleaseVertexElements(); } Cube::Cube( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions - ) { - initialize(x, y, z, s, r, g, b, faceExclusions); + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ) { + initialize(x, y, z, s, r, g, b, faceExclusions); } Cube::~Cube() { - terminate(); + terminate(); } void Cube::initialize( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions - ) { + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ) { - initializeVertices(x, y, z, s, r, g, b, faceExclusions); - initializeTris(faceExclusions); + initializeVertices(x, y, z, s, r, g, b, faceExclusions); + initializeTris(faceExclusions); } void Cube::terminate() { - terminateTris(); - terminateVertices(); + terminateTris(); + terminateVertices(); } void Cube::initializeVertices( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions - ) { + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ) { - for (int i = 0; i < _sNumVerticesPerCube; i++) { - // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. - if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { - //if (~0x00 & _sFaceIndexToHalfSpaceMask[i >> 2]) { - //if (faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { + for (int i = 0; i < _sNumVerticesPerCube; i++) { + // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. + if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { + //if (~0x00 & _sFaceIndexToHalfSpaceMask[i >> 2]) { + //if (faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { - VertexElement* v = new VertexElement(); - if (v) { - // Construct vertex position - v->position.x = x + s * _sVertexIndexToConstructionVector[i][0]; - v->position.y = y + s * _sVertexIndexToConstructionVector[i][1]; - v->position.z = z + s * _sVertexIndexToConstructionVector[i][2]; + VertexElement* v = new VertexElement(); + if (v) { + // Construct vertex position + v->position.x = x + s * _sVertexIndexToConstructionVector[i][0]; + v->position.y = y + s * _sVertexIndexToConstructionVector[i][1]; + v->position.z = z + s * _sVertexIndexToConstructionVector[i][2]; - // Construct vertex normal - v->normal.x = _sVertexIndexToNormalVector[i >> 2][0]; - v->normal.y = _sVertexIndexToNormalVector[i >> 2][1]; - v->normal.z = _sVertexIndexToNormalVector[i >> 2][2]; + // Construct vertex normal + v->normal.x = _sVertexIndexToNormalVector[i >> 2][0]; + v->normal.y = _sVertexIndexToNormalVector[i >> 2][1]; + v->normal.z = _sVertexIndexToNormalVector[i >> 2][2]; - // Construct vertex color + // Construct vertex color //#define FALSE_COLOR #ifndef FALSE_COLOR - v->color.r = r; - v->color.g = g; - v->color.b = b; - v->color.a = 255; + v->color.r = r; + v->color.g = g; + v->color.b = b; + v->color.a = 255; #else - static unsigned char falseColor[6][3] = { - 192, 0, 0, // Bot - 0, 192, 0, // Top - 0, 0, 192, // Right - 192, 0, 192, // Left - 192, 192, 0, // Near - 192, 192, 192 // Far - }; - v->color.r = falseColor[i >> 2][0]; - v->color.g = falseColor[i >> 2][1]; - v->color.b = falseColor[i >> 2][2]; - v->color.a = 255; + static unsigned char falseColor[6][3] = { + 192, 0, 0, // Bot + 0, 192, 0, // Top + 0, 0, 192, // Right + 192, 0, 192, // Left + 192, 192, 0, // Near + 192, 192, 192 // Far + }; + v->color.r = falseColor[i >> 2][0]; + v->color.g = falseColor[i >> 2][1]; + v->color.b = falseColor[i >> 2][2]; + v->color.a = 255; #endif - // Add vertex element to list - _vertices.push_back(v); - } - } - } + // Add vertex element to list + _vertices.push_back(v); + } + } + } } void Cube::terminateVertices() { - VertexElementList::iterator it = _vertices.begin(); - VertexElementList::iterator end = _vertices.end(); + VertexElementList::iterator it = _vertices.begin(); + VertexElementList::iterator end = _vertices.end(); - for ( ; it != end; ++it) { - delete *it; - } - _vertices.clear(); + for ( ; it != end; ++it) { + delete *it; + } + _vertices.clear(); } void Cube::initializeTris( - unsigned char faceExclusions - ) { + unsigned char faceExclusions + ) { - int index = 0; - for (int i = 0; i < _sNumFacesPerCube; i++) { - // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. - // uncomment this line to exclude shared faces: - if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { - // uncomment this line to load all faces: if (~0x00 & _sFaceIndexToHalfSpaceMask[i]) { - // uncomment this line to include shared faces: if (faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { - - int start = index; - // Create the triangulated face, two tris, six indices referencing four vertices, both - // with cw winding order, such that: + int index = 0; + for (int i = 0; i < _sNumFacesPerCube; i++) { + // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. + // uncomment this line to exclude shared faces: + if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { + // uncomment this line to load all faces: if (~0x00 & _sFaceIndexToHalfSpaceMask[i]) { + // uncomment this line to include shared faces: if (faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { + + int start = index; + // Create the triangulated face, two tris, six indices referencing four vertices, both + // with cw winding order, such that: - // A-B - // |\| - // D-C + // A-B + // |\| + // D-C - // Store triangle ABC + // Store triangle ABC - TriElement *tri = new TriElement(); - if (tri) { - tri->indices[0] = index++; - tri->indices[1] = index++; - tri->indices[2] = index; + TriElement *tri = new TriElement(); + if (tri) { + tri->indices[0] = index++; + tri->indices[1] = index++; + tri->indices[2] = index; - // Add tri element to list - _tris.push_back(tri); - } + // Add tri element to list + _tris.push_back(tri); + } - // Now store triangle ACD - tri = new TriElement(); - if (tri) { - tri->indices[0] = start; - tri->indices[1] = index++; - tri->indices[2] = index++; + // Now store triangle ACD + tri = new TriElement(); + if (tri) { + tri->indices[0] = start; + tri->indices[1] = index++; + tri->indices[2] = index++; - // Add tri element to list - _tris.push_back(tri); - } - } - } + // Add tri element to list + _tris.push_back(tri); + } + } + } } void Cube::terminateTris() { - TriElementList::iterator it = _tris.begin(); - TriElementList::iterator end = _tris.end(); + TriElementList::iterator it = _tris.begin(); + TriElementList::iterator end = _tris.end(); - for ( ; it != end; ++it) { - delete *it; - } - _tris.clear(); + for ( ; it != end; ++it) { + delete *it; + } + _tris.clear(); } VertexElementList const & Cube::vVertexElements() const { - return _vertices; + return _vertices; } VertexElementIndexList& Cube::vVertexElementIndices() { - return _vertexIndices; + return _vertexIndices; } TriElementList& Cube::vTriElements() { - return _tris; + return _tris; } void Cube::vReleaseVertexElements() { - terminateVertices(); + terminateVertices(); } unsigned char Cube::_sFaceIndexToHalfSpaceMask[6] = { - OctreeElement::HalfSpace::Bottom, - OctreeElement::HalfSpace::Top, - OctreeElement::HalfSpace::Right, - OctreeElement::HalfSpace::Left, - OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Far, + OctreeElement::HalfSpace::Bottom, + OctreeElement::HalfSpace::Top, + OctreeElement::HalfSpace::Right, + OctreeElement::HalfSpace::Left, + OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Far, }; #define CW_CONSTRUCTION @@ -228,82 +228,82 @@ unsigned char Cube::_sFaceIndexToHalfSpaceMask[6] = { // Construction vectors ordered such that the vertices of each face are // CW in a right-handed coordinate system with B-L-N at 0,0,0. float Cube::_sVertexIndexToConstructionVector[24][3] = { - // Bottom - { 0,0,0 }, - { 1,0,0 }, - { 1,0,1 }, - { 0,0,1 }, - // Top - { 0,1,0 }, - { 0,1,1 }, - { 1,1,1 }, - { 1,1,0 }, - // Right - { 1,0,0 }, - { 1,1,0 }, - { 1,1,1 }, - { 1,0,1 }, - // Left - { 0,0,0 }, - { 0,0,1 }, - { 0,1,1 }, - { 0,1,0 }, - // Near - { 0,0,0 }, - { 0,1,0 }, - { 1,1,0 }, - { 1,0,0 }, - // Far - { 0,0,1 }, - { 1,0,1 }, - { 1,1,1 }, - { 0,1,1 }, + // Bottom + { 0,0,0 }, + { 1,0,0 }, + { 1,0,1 }, + { 0,0,1 }, + // Top + { 0,1,0 }, + { 0,1,1 }, + { 1,1,1 }, + { 1,1,0 }, + // Right + { 1,0,0 }, + { 1,1,0 }, + { 1,1,1 }, + { 1,0,1 }, + // Left + { 0,0,0 }, + { 0,0,1 }, + { 0,1,1 }, + { 0,1,0 }, + // Near + { 0,0,0 }, + { 0,1,0 }, + { 1,1,0 }, + { 1,0,0 }, + // Far + { 0,0,1 }, + { 1,0,1 }, + { 1,1,1 }, + { 0,1,1 }, }; #else // CW_CONSTRUCTION // Construction vectors ordered such that the vertices of each face are // CCW in a right-handed coordinate system with B-L-N at 0,0,0. float Cube::_sVertexIndexToConstructionVector[24][3] = { - // Bottom - { 0,0,0 }, - { 0,0,1 }, - { 1,0,1 }, - { 1,0,0 }, - // Top - { 0,1,0 }, - { 1,1,0 }, - { 1,1,1 }, - { 0,1,1 }, - // Right - { 1,0,0 }, - { 1,0,1 }, - { 1,1,1 }, - { 1,1,0 }, - // Left - { 0,0,0 }, - { 0,1,0 }, - { 0,1,1 }, - { 0,0,1 }, - // Near - { 0,0,0 }, - { 1,0,0 }, - { 1,1,0 }, - { 0,1,0 }, - // Far - { 0,0,1 }, - { 0,1,1 }, - { 1,1,1 }, - { 1,0,1 }, + // Bottom + { 0,0,0 }, + { 0,0,1 }, + { 1,0,1 }, + { 1,0,0 }, + // Top + { 0,1,0 }, + { 1,1,0 }, + { 1,1,1 }, + { 0,1,1 }, + // Right + { 1,0,0 }, + { 1,0,1 }, + { 1,1,1 }, + { 1,1,0 }, + // Left + { 0,0,0 }, + { 0,1,0 }, + { 0,1,1 }, + { 0,0,1 }, + // Near + { 0,0,0 }, + { 1,0,0 }, + { 1,1,0 }, + { 0,1,0 }, + // Far + { 0,0,1 }, + { 0,1,1 }, + { 1,1,1 }, + { 1,0,1 }, }; #endif // Normals for a right-handed coordinate system float Cube::_sVertexIndexToNormalVector[6][3] = { - { 0,-1, 0 }, // Bottom - { 0, 1, 0 }, // Top - { 1, 0, 0 }, // Right - { -1, 0, 0 }, // Left - { 0, 0,-1 }, // Near - { 0, 0, 1 }, // Far + { 0,-1, 0 }, // Bottom + { 0, 1, 0 }, // Top + { 1, 0, 0 }, // Right + { -1, 0, 0 }, // Left + { 0, 0,-1 }, // Near + { 0, 0, 1 }, // Far }; Renderer::Renderer() { @@ -314,377 +314,377 @@ Renderer::~Renderer() { // Simple dispatch between API and SPI int Renderer::add( - Primitive* primitive - ) { - return vAdd(primitive); + Primitive* primitive + ) { + return vAdd(primitive); } void Renderer::remove( - int id - ) { - vRemove(id); + int id + ) { + vRemove(id); } void Renderer::render() { - vRender(); + vRender(); } PrimitiveRenderer::PrimitiveRenderer( - int maxCount - ) : - _maxCount(maxCount), - _vertexElementCount(0), - _maxVertexElementCount(maxCount), - _triElementCount(0), - _maxTriElementCount(maxCount), - _primitiveCount(0), + int maxCount + ) : + _maxCount(maxCount), + _vertexElementCount(0), + _maxVertexElementCount(maxCount), + _triElementCount(0), + _maxTriElementCount(maxCount), + _primitiveCount(0), - _triBufferId(0), - _vertexBufferId(0), + _triBufferId(0), + _vertexBufferId(0), - _gpuMemoryUsage(0), - _cpuMemoryUsage(0) + _gpuMemoryUsage(0), + _cpuMemoryUsage(0) { - initialize(); + initialize(); } PrimitiveRenderer::~PrimitiveRenderer() { - terminate(); + terminate(); } void PrimitiveRenderer::initialize() { - initializeGL(); - initializeBookkeeping(); + initializeGL(); + initializeBookkeeping(); } void PrimitiveRenderer::initializeGL() { - glGenBuffers(1, &_triBufferId); - glGenBuffers(1, &_vertexBufferId); + glGenBuffers(1, &_triBufferId); + glGenBuffers(1, &_vertexBufferId); - // Set up the element array buffer containing the index ids - int size = _maxCount * sizeof(GLint) * 3; - _gpuMemoryUsage += size; + // Set up the element array buffer containing the index ids + int size = _maxCount * sizeof(GLint) * 3; + _gpuMemoryUsage += size; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - // Set up the array buffer in the form of array of structures - // I chose AOS because it maximizes the amount of data tranferred - // by a single glBufferSubData call. - size = _maxCount * sizeof(VertexElement); - _gpuMemoryUsage += size; + // Set up the array buffer in the form of array of structures + // I chose AOS because it maximizes the amount of data tranferred + // by a single glBufferSubData call. + size = _maxCount * sizeof(VertexElement); + _gpuMemoryUsage += size; - glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); - glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); + glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); - // Initialize the first vertex element in the buffer to all zeros, the - // degenerate case - _vertexElementCount = 1; - _triElementCount = 1; + // Initialize the first vertex element in the buffer to all zeros, the + // degenerate case + _vertexElementCount = 1; + _triElementCount = 1; - VertexElement v; - memset(&v, 0, sizeof(v)); + VertexElement v; + memset(&v, 0, sizeof(v)); - transferVertexElement(0, &v); - deconstructTriElement(0); + transferVertexElement(0, &v); + deconstructTriElement(0); - GLint err = glGetError(); + GLint err = glGetError(); } void PrimitiveRenderer::initializeBookkeeping() { - // Start primitive count at one, because zero is reserved for the degenerate triangle - _primitiveCount = 1; - _cpuMemoryUsage = sizeof(PrimitiveRenderer); + // Start primitive count at one, because zero is reserved for the degenerate triangle + _primitiveCount = 1; + _cpuMemoryUsage = sizeof(PrimitiveRenderer); } void PrimitiveRenderer::terminate() { - terminateBookkeeping(); - terminateGL(); + terminateBookkeeping(); + terminateGL(); } void PrimitiveRenderer::terminateGL() { - glDeleteBuffers(1, &_vertexBufferId); - glDeleteBuffers(1, &_triBufferId); - GLint err = glGetError(); + glDeleteBuffers(1, &_vertexBufferId); + glDeleteBuffers(1, &_triBufferId); + GLint err = glGetError(); } void PrimitiveRenderer::terminateBookkeeping() { - // Drain all of the queues, stop updating the counters - while (_availableVertexElementIndex.remove() != 0) - ; + // Drain all of the queues, stop updating the counters + while (_availableVertexElementIndex.remove() != 0) + ; - while (_availableTriElementIndex.remove() != 0) - ; + while (_availableTriElementIndex.remove() != 0) + ; - while (_deconstructTriElementIndex.remove() != 0) - ; + while (_deconstructTriElementIndex.remove() != 0) + ; - std::map::iterator it = _indexToPrimitiveMap.begin(); - std::map::iterator end = _indexToPrimitiveMap.end(); + std::map::iterator it = _indexToPrimitiveMap.begin(); + std::map::iterator end = _indexToPrimitiveMap.end(); - for ( ; it != end; ++it) { - Primitive *primitive = it->second; - delete primitive; - } + for ( ; it != end; ++it) { + Primitive *primitive = it->second; + delete primitive; + } } int PrimitiveRenderer::vAdd( - Primitive* primitive - ) { + Primitive* primitive + ) { - int index = getAvailablePrimitiveIndex(); - if (index != 0) { - try { - // Take ownership of primitive, including responsibility - // for destruction - _indexToPrimitiveMap[index] = primitive; - constructElements(primitive); + int index = getAvailablePrimitiveIndex(); + if (index != 0) { + try { + // Take ownership of primitive, including responsibility + // for destruction + _indexToPrimitiveMap[index] = primitive; + constructElements(primitive); - // No need to keep an extra copy of the vertices - primitive->releaseVertexElements(); - } catch(...) { - // STL failed, recycle the index - _availablePrimitiveIndex.add(index); - index = 0; - } - } - return index; + // No need to keep an extra copy of the vertices + primitive->releaseVertexElements(); + } catch(...) { + // STL failed, recycle the index + _availablePrimitiveIndex.add(index); + index = 0; + } + } + return index; } void PrimitiveRenderer::vRemove( - int index - ) { + int index + ) { - try { + try { - // Locate the primitive by id in the associative map - std::map::iterator it = _indexToPrimitiveMap.find(index); - if (it != _indexToPrimitiveMap.end()) { - Primitive *primitive = it->second; - if (primitive) { - _indexToPrimitiveMap[index] = 0; - deconstructElements(primitive); - _availablePrimitiveIndex.add(index); - } - // Not necessary to remove the item from the associative map, because - // the index is going to be re-used, but if you want to... uncomment the following: - //_indexToPrimitiveMap.erase(it); - } - } catch(...) { - // STL failed - } + // Locate the primitive by id in the associative map + std::map::iterator it = _indexToPrimitiveMap.find(index); + if (it != _indexToPrimitiveMap.end()) { + Primitive *primitive = it->second; + if (primitive) { + _indexToPrimitiveMap[index] = 0; + deconstructElements(primitive); + _availablePrimitiveIndex.add(index); + } + // Not necessary to remove the item from the associative map, because + // the index is going to be re-used, but if you want to... uncomment the following: + //_indexToPrimitiveMap.erase(it); + } + } catch(...) { + // STL failed + } } void PrimitiveRenderer::constructElements( - Primitive* primitive - ) { + Primitive* primitive + ) { - // Load vertex elements - VertexElementIndexList& vertexElementIndexList = primitive->vertexElementIndices(); - { - VertexElementList const & vertices = primitive->vertexElements(); - VertexElementList::const_iterator it = vertices.begin(); - VertexElementList::const_iterator end = vertices.end(); + // Load vertex elements + VertexElementIndexList& vertexElementIndexList = primitive->vertexElementIndices(); + { + VertexElementList const & vertices = primitive->vertexElements(); + VertexElementList::const_iterator it = vertices.begin(); + VertexElementList::const_iterator end = vertices.end(); - for ( ; it != end; ++it ) { - int index = getAvailableVertexElementIndex(); - if (index != 0) { - vertexElementIndexList.push_back(index); - VertexElement* vertex = *it; - transferVertexElement(index, vertex); - } - } - } + for ( ; it != end; ++it ) { + int index = getAvailableVertexElementIndex(); + if (index != 0) { + vertexElementIndexList.push_back(index); + VertexElement* vertex = *it; + transferVertexElement(index, vertex); + } + } + } - // Load tri elements - { - TriElementList& tris = primitive->triElements(); - TriElementList::iterator it = tris.begin(); - TriElementList::iterator end = tris.end(); + // Load tri elements + { + TriElementList& tris = primitive->triElements(); + TriElementList::iterator it = tris.begin(); + TriElementList::iterator end = tris.end(); - for ( ; it != end; ++it) { - TriElement* tri = *it; - int index = getAvailableTriElementIndex(); - if (index != 0) { - int k; - k = tri->indices[0]; - tri->indices[0] = vertexElementIndexList[k]; + for ( ; it != end; ++it) { + TriElement* tri = *it; + int index = getAvailableTriElementIndex(); + if (index != 0) { + int k; + k = tri->indices[0]; + tri->indices[0] = vertexElementIndexList[k]; - k = tri->indices[1]; - tri->indices[1] = vertexElementIndexList[k]; + k = tri->indices[1]; + tri->indices[1] = vertexElementIndexList[k]; - k = tri->indices[2]; - tri->indices[2] = vertexElementIndexList[k]; + k = tri->indices[2]; + tri->indices[2] = vertexElementIndexList[k]; - tri->id = index; - transferTriElement(index, tri->indices); - } - } - } + tri->id = index; + transferTriElement(index, tri->indices); + } + } + } } void PrimitiveRenderer::deconstructElements( - Primitive* primitive - ) { + Primitive* primitive + ) { - // Schedule the tri elements of the face for deconstruction - { - TriElementList& tris = primitive->triElements(); - TriElementList::iterator it = tris.begin(); - TriElementList::iterator end = tris.end(); + // Schedule the tri elements of the face for deconstruction + { + TriElementList& tris = primitive->triElements(); + TriElementList::iterator it = tris.begin(); + TriElementList::iterator end = tris.end(); - for ( ; it != end; ++it) { - TriElement* tri = *it; + for ( ; it != end; ++it) { + TriElement* tri = *it; - // Put the tri element index into decon queue - _deconstructTriElementIndex.add(tri->id); - } - } - // Return the vertex element index to the available queue, it is not necessary - // to zero the data - { - VertexElementIndexList& vertexIndexList = primitive->vertexElementIndices(); - VertexElementIndexList::iterator it = vertexIndexList.begin(); - VertexElementIndexList::iterator end = vertexIndexList.end(); + // Put the tri element index into decon queue + _deconstructTriElementIndex.add(tri->id); + } + } + // Return the vertex element index to the available queue, it is not necessary + // to zero the data + { + VertexElementIndexList& vertexIndexList = primitive->vertexElementIndices(); + VertexElementIndexList::iterator it = vertexIndexList.begin(); + VertexElementIndexList::iterator end = vertexIndexList.end(); - for ( ; it != end; ++it) { - int index = *it; + for ( ; it != end; ++it) { + int index = *it; - // Put the vertex element index into the available queue - _availableVertexElementIndex.add(index); - } - } + // Put the vertex element index into the available queue + _availableVertexElementIndex.add(index); + } + } - // destroy primitive - delete primitive; + // destroy primitive + delete primitive; } int PrimitiveRenderer::getAvailablePrimitiveIndex() { - // Check the available primitive index queue first for an available index. - int index = _availablePrimitiveIndex.remove(); - // Remember that the primitive index 0 is used not used. - if (index == 0) { - // There are no primitive indices available from the queue, - // make one up - index = _primitiveCount++; - } - return index; + // Check the available primitive index queue first for an available index. + int index = _availablePrimitiveIndex.remove(); + // Remember that the primitive index 0 is used not used. + if (index == 0) { + // There are no primitive indices available from the queue, + // make one up + index = _primitiveCount++; + } + return index; } int PrimitiveRenderer::getAvailableVertexElementIndex() { - // Check the available vertex element queue first for an available index. - int index = _availableVertexElementIndex.remove(); - // Remember that the vertex element 0 is used for degenerate triangles. - if (index == 0) { - // There are no vertex elements available from the queue, - // grab one from the end of the list - if (_vertexElementCount < _maxVertexElementCount) { - index = _vertexElementCount++; - } - } - return index; + // Check the available vertex element queue first for an available index. + int index = _availableVertexElementIndex.remove(); + // Remember that the vertex element 0 is used for degenerate triangles. + if (index == 0) { + // There are no vertex elements available from the queue, + // grab one from the end of the list + if (_vertexElementCount < _maxVertexElementCount) { + index = _vertexElementCount++; + } + } + return index; } int PrimitiveRenderer::getAvailableTriElementIndex() { - // Check the deconstruct tri element queue first for an available index. - int index = _deconstructTriElementIndex.remove(); - // Remember that the tri element 0 is used for degenerate triangles. - if (index == 0) { - // There are no tri elements in the deconstruct tri element queue that are reusable. - // Check the available tri element queue. - index = _availableTriElementIndex.remove(); - if (index == 0) { - // There are no reusable tri elements available from any queue, - // grab one from the end of the list - if (_triElementCount < _maxTriElementCount) { - index = _triElementCount++; - } - } - } - return index; + // Check the deconstruct tri element queue first for an available index. + int index = _deconstructTriElementIndex.remove(); + // Remember that the tri element 0 is used for degenerate triangles. + if (index == 0) { + // There are no tri elements in the deconstruct tri element queue that are reusable. + // Check the available tri element queue. + index = _availableTriElementIndex.remove(); + if (index == 0) { + // There are no reusable tri elements available from any queue, + // grab one from the end of the list + if (_triElementCount < _maxTriElementCount) { + index = _triElementCount++; + } + } + } + return index; } void PrimitiveRenderer::deconstructTriElement( - int idx - ) { + int idx + ) { - // Set the element to the degenerate case. - int degenerate[3] = { 0, 0, 0 }; - transferTriElement(idx, degenerate); + // Set the element to the degenerate case. + int degenerate[3] = { 0, 0, 0 }; + transferTriElement(idx, degenerate); } void PrimitiveRenderer::transferVertexElement( - int idx, - VertexElement* vertex - ) { + int idx, + VertexElement* vertex + ) { - glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); - glBufferSubData(GL_ARRAY_BUFFER, idx * sizeof(VertexElement), sizeof(VertexElement), vertex); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); + glBufferSubData(GL_ARRAY_BUFFER, idx * sizeof(VertexElement), sizeof(VertexElement), vertex); + glBindBuffer(GL_ARRAY_BUFFER, 0); } void PrimitiveRenderer::transferTriElement( - int idx, - int tri[3] - ) { + int idx, + int tri[3] + ) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, idx * sizeof(GLint) * 3, sizeof(GLint) * 3, tri); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, idx * sizeof(GLint) * 3, sizeof(GLint) * 3, tri); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } void PrimitiveRenderer::vRender() { - // Now would be an appropriate time to set the element array buffer ids - // scheduled for deconstruction to the degenerate case. - int id; - while ((id = _deconstructTriElementIndex.remove()) != 0) { - deconstructTriElement(id); - _availableTriElementIndex.add(id); - } + // Now would be an appropriate time to set the element array buffer ids + // scheduled for deconstruction to the degenerate case. + int id; + while ((id = _deconstructTriElementIndex.remove()) != 0) { + deconstructTriElement(id); + _availableTriElementIndex.add(id); + } - // The application uses clockwise winding for the definition of front face, but I - // arbitrarily chose counter-clockwise (that is the gl default) to construct the triangulation - // so... - //glFrontFace(GL_CCW); - glEnable(GL_CULL_FACE); + // The application uses clockwise winding for the definition of front face, but I + // arbitrarily chose counter-clockwise (that is the gl default) to construct the triangulation + // so... + //glFrontFace(GL_CCW); + glEnable(GL_CULL_FACE); - glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); + glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexElement), 0); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(VertexElement), 0); - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexElement), (GLvoid const *)12); + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, sizeof(VertexElement), (GLvoid const *)12); - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexElement), (GLvoid const *)24); + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexElement), (GLvoid const *)24); - glBindBuffer(GL_ARRAY_BUFFER, 0); - GLint err = glGetError(); + glBindBuffer(GL_ARRAY_BUFFER, 0); + GLint err = glGetError(); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); - glDrawElements(GL_TRIANGLES, 3 * _triElementCount, GL_UNSIGNED_INT, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); + glDrawElements(GL_TRIANGLES, 3 * _triElementCount, GL_UNSIGNED_INT, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glDisable(GL_CULL_FACE); + glDisable(GL_CULL_FACE); - // TODO: does the interface ever change the winding order? - //glFrontFace(GL_CW); - err = glGetError(); + // TODO: does the interface ever change the winding order? + //glFrontFace(GL_CW); + err = glGetError(); } diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/PrimitiveRenderer.h index 24fee66184..f2ebfe23f4 100644 --- a/interface/src/PrimitiveRenderer.h +++ b/interface/src/PrimitiveRenderer.h @@ -1,9 +1,9 @@ /// -/// @file PrimitiveRenderer.h -/// A geometric primitive renderer. +/// @file PrimitiveRenderer.h +/// A geometric primitive renderer. /// -/// @author: Norman Crafts -/// @copyright 2014, High Fidelity, Inc. All rights reserved. +/// @author: Norman Crafts +/// @copyright 2014, High Fidelity, Inc. All rights reserved. /// #ifndef __interface__PrimitiveRenderer__ @@ -13,399 +13,399 @@ #include "Queue.h" /// Vertex element structure. -/// Using the array of structures approach to specifying -/// vertex data to GL cuts down on the calls to glBufferSubData +/// Using the array of structures approach to specifying +/// vertex data to GL cuts down on the calls to glBufferSubData /// typedef - struct __VertexElement { - struct __position { - float x; - float y; - float z; - } position; - struct __normal { - float x; - float y; - float z; - } normal; - struct __color { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; - } color; - } VertexElement; + struct __VertexElement { + struct __position { + float x; + float y; + float z; + } position; + struct __normal { + float x; + float y; + float z; + } normal; + struct __color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } color; + } VertexElement; /// Triangle element index structure. -/// Specify the vertex indices of the triangle and its element index. +/// Specify the vertex indices of the triangle and its element index. /// typedef - struct __TriElement { - int indices[3]; - int id; + struct __TriElement { + int indices[3]; + int id; - } TriElement; + } TriElement; typedef std::vector > VertexElementList; typedef std::vector > VertexElementIndexList; typedef std::vector > TriElementList; /// -/// @class Primitive -/// Primitive Interface class. -/// Abstract class for accessing vertex and tri elements of geometric primitives +/// @class Primitive +/// Primitive Interface class. +/// Abstract class for accessing vertex and tri elements of geometric primitives /// /// class Primitive { public: - virtual ~Primitive(); + virtual ~Primitive(); - // API methods go here + // API methods go here - /// Vertex element accessor. - /// @return A list of vertex elements of the primitive - /// - VertexElementList const & vertexElements() const; + /// Vertex element accessor. + /// @return A list of vertex elements of the primitive + /// + VertexElementList const & vertexElements() const; - /// Vertex element index accessor. - /// @return A list of vertex element indices of the primitive - /// - VertexElementIndexList& vertexElementIndices(); + /// Vertex element index accessor. + /// @return A list of vertex element indices of the primitive + /// + VertexElementIndexList& vertexElementIndices(); - /// Tri element accessor. - /// @return A list of tri elements of the primitive - /// - TriElementList& triElements(); + /// Tri element accessor. + /// @return A list of tri elements of the primitive + /// + TriElementList& triElements(); - /// Release vertex elements. - /// - void releaseVertexElements(); + /// Release vertex elements. + /// + void releaseVertexElements(); protected: - /// Default constructor prohibited to API user, restricted to service implementer. - /// - Primitive(); + /// Default constructor prohibited to API user, restricted to service implementer. + /// + Primitive(); private: - /// Copy constructor prohibited. - /// - Primitive( - Primitive const & prim - ); + /// Copy constructor prohibited. + /// + Primitive( + Primitive const & prim + ); - // SPI methods are defined here + // SPI methods are defined here - /// Vertex element accessor. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual VertexElementList const & vVertexElements() const = 0; + /// Vertex element accessor. + /// Service implementer to provide private override for this method + /// in derived class + /// + virtual VertexElementList const & vVertexElements() const = 0; - /// Vertex element index accessor. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual VertexElementIndexList& vVertexElementIndices() = 0; + /// Vertex element index accessor. + /// Service implementer to provide private override for this method + /// in derived class + /// + virtual VertexElementIndexList& vVertexElementIndices() = 0; - /// Tri element accessor. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual TriElementList& vTriElements() = 0; + /// Tri element accessor. + /// Service implementer to provide private override for this method + /// in derived class + /// + virtual TriElementList& vTriElements() = 0; - /// Release vertex elements. - /// - virtual void vReleaseVertexElements() = 0; + /// Release vertex elements. + /// + virtual void vReleaseVertexElements() = 0; }; /// -/// @class Cube -/// Class for accessing the vertex and tri elements of a cube +/// @class Cube +/// Class for accessing the vertex and tri elements of a cube /// class Cube: public Primitive { public: - /// Configuration dependency injection constructor. - /// - Cube( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faces - ); + /// Configuration dependency injection constructor. + /// + Cube( + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faces + ); - ~Cube(); + ~Cube(); private: - /// Copy constructor prohibited. - /// - Cube ( - Cube const & cube - ); + /// Copy constructor prohibited. + /// + Cube ( + Cube const & cube + ); - void initialize( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions - ); + void initialize( + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ); - void terminate(); + void terminate(); - void initializeVertices( - float x, - float y, - float z, - float s, - unsigned char r, - unsigned char g, - unsigned char b, - unsigned char faceExclusions - ); + void initializeVertices( + float x, + float y, + float z, + float s, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char faceExclusions + ); - void terminateVertices(); + void terminateVertices(); - void initializeTris( - unsigned char faceExclusions - ); + void initializeTris( + unsigned char faceExclusions + ); - void terminateTris(); + void terminateTris(); - // SPI virtual override methods go here + // SPI virtual override methods go here - VertexElementList const & vVertexElements() const; - VertexElementIndexList& vVertexElementIndices(); - TriElementList& vTriElements(); - void vReleaseVertexElements(); + VertexElementList const & vVertexElements() const; + VertexElementIndexList& vVertexElementIndices(); + TriElementList& vTriElements(); + void vReleaseVertexElements(); private: - VertexElementList _vertices; ///< Vertex element list - VertexElementIndexList _vertexIndices; ///< Vertex element index list - TriElementList _tris; ///< Tri element list + VertexElementList _vertices; ///< Vertex element list + VertexElementIndexList _vertexIndices; ///< Vertex element index list + TriElementList _tris; ///< Tri element list - static const int _sNumFacesPerCube = 6; - static const int _sNumVerticesPerCube = 24; - static unsigned char _sFaceIndexToHalfSpaceMask[6]; - static float _sVertexIndexToConstructionVector[24][3]; - static float _sVertexIndexToNormalVector[6][3]; + static const int _sNumFacesPerCube = 6; + static const int _sNumVerticesPerCube = 24; + static unsigned char _sFaceIndexToHalfSpaceMask[6]; + static float _sVertexIndexToConstructionVector[24][3]; + static float _sVertexIndexToNormalVector[6][3]; }; /// -/// @class Renderer -/// GL renderer interface class. -/// Abstract class for rendering geometric primitives in GL +/// @class Renderer +/// GL renderer interface class. +/// Abstract class for rendering geometric primitives in GL /// class Renderer { public: - virtual ~Renderer(); + virtual ~Renderer(); - // API methods go here + // API methods go here - /// Add primitive to renderer database. - /// - int add( - Primitive* primitive ///< Pointer to primitive - ); + /// Add primitive to renderer database. + /// + int add( + Primitive* primitive ///< Pointer to primitive + ); - /// Remove primitive from renderer database. - /// - void remove( - int id ///< Primitive id - ); + /// Remove primitive from renderer database. + /// + void remove( + int id ///< Primitive id + ); - /// Render primitive database. - /// The render method assumes appropriate GL context and state has - /// already been provided for - /// - void render(); + /// Render primitive database. + /// The render method assumes appropriate GL context and state has + /// already been provided for + /// + void render(); protected: - /// Default constructor prohibited to API user, restricted to service implementer. - /// - Renderer(); + /// Default constructor prohibited to API user, restricted to service implementer. + /// + Renderer(); private: - /// Copy constructor prohibited. - /// - Renderer( - Renderer const & primitive - ); + /// Copy constructor prohibited. + /// + Renderer( + Renderer const & primitive + ); - // SPI methods are defined here + // SPI methods are defined here - /// Add primitive to renderer database. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual int vAdd( - Primitive* primitive ///< Pointer to primitive - ) = 0; + /// Add primitive to renderer database. + /// Service implementer to provide private override for this method + /// in derived class + /// + virtual int vAdd( + Primitive* primitive ///< Pointer to primitive + ) = 0; - /// Remove primitive from renderer database. - /// Service implementer to provide private override for this method - /// in derived class - /// - virtual void vRemove( - int id ///< Primitive id - ) = 0; + /// Remove primitive from renderer database. + /// Service implementer to provide private override for this method + /// in derived class + /// + virtual void vRemove( + int id ///< Primitive id + ) = 0; - /// Render primitive database. - /// Service implementer to provide private virtual override for this method - /// in derived class - /// - virtual void vRender() = 0; + /// Render primitive database. + /// Service implementer to provide private virtual override for this method + /// in derived class + /// + virtual void vRender() = 0; }; /// -/// @class PrimitiveRenderer -/// Renderer implementation class for the rendering of geometric primitives -/// using GL element array and GL array buffers +/// @class PrimitiveRenderer +/// Renderer implementation class for the rendering of geometric primitives +/// using GL element array and GL array buffers /// class PrimitiveRenderer : public Renderer { public: - /// Configuration dependency injection constructor. - /// - PrimitiveRenderer( - int maxCount - ); + /// Configuration dependency injection constructor. + /// + PrimitiveRenderer( + int maxCount + ); - ~PrimitiveRenderer(); + ~PrimitiveRenderer(); private: - /// Default constructor prohibited. - /// - PrimitiveRenderer(); + /// Default constructor prohibited. + /// + PrimitiveRenderer(); - /// Copy constructor prohibited. - /// - PrimitiveRenderer( - PrimitiveRenderer const & renderer - ); + /// Copy constructor prohibited. + /// + PrimitiveRenderer( + PrimitiveRenderer const & renderer + ); - void initialize(); - void terminate(); + void initialize(); + void terminate(); - /// Allocate and initialize GL buffers. - /// - void initializeGL(); + /// Allocate and initialize GL buffers. + /// + void initializeGL(); - /// Terminate and deallocate GL buffers. - /// - void terminateGL(); + /// Terminate and deallocate GL buffers. + /// + void terminateGL(); - void initializeBookkeeping(); - void terminateBookkeeping(); + void initializeBookkeeping(); + void terminateBookkeeping(); - /// Construct the elements of the faces of the primitive. - /// - void constructElements( - Primitive* primitive - ); + /// Construct the elements of the faces of the primitive. + /// + void constructElements( + Primitive* primitive + ); - /// Deconstruct the elements of the faces of the primitive. - /// - void deconstructElements( - Primitive* primitive - ); + /// Deconstruct the elements of the faces of the primitive. + /// + void deconstructElements( + Primitive* primitive + ); - /// Deconstruct the triangle element from the GL buffer. - /// - void deconstructTriElement( - int idx - ); + /// Deconstruct the triangle element from the GL buffer. + /// + void deconstructTriElement( + int idx + ); - /// Transfer the vertex element to the GL buffer. - /// - void transferVertexElement( - int idx, - VertexElement *vertex - ); + /// Transfer the vertex element to the GL buffer. + /// + void transferVertexElement( + int idx, + VertexElement *vertex + ); - /// Transfer the triangle element to the GL buffer. - /// - void transferTriElement( - int idx, - int tri[3] - ); + /// Transfer the triangle element to the GL buffer. + /// + void transferTriElement( + int idx, + int tri[3] + ); - /// Get available primitive index. - /// Get an available primitive index from either the recycling - /// queue or incrementing the counter - /// - int getAvailablePrimitiveIndex(); + /// Get available primitive index. + /// Get an available primitive index from either the recycling + /// queue or incrementing the counter + /// + int getAvailablePrimitiveIndex(); - /// Get available vertex element index. - /// Get an available vertex element index from either the recycling - /// queue or incrementing the counter - /// - int getAvailableVertexElementIndex(); + /// Get available vertex element index. + /// Get an available vertex element index from either the recycling + /// queue or incrementing the counter + /// + int getAvailableVertexElementIndex(); - /// Get available triangle element index. - /// Get an available triangle element index from either the elements - /// scheduled for deconstruction queue, the recycling - /// queue or incrementing the counter - /// - int getAvailableTriElementIndex(); + /// Get available triangle element index. + /// Get an available triangle element index from either the elements + /// scheduled for deconstruction queue, the recycling + /// queue or incrementing the counter + /// + int getAvailableTriElementIndex(); - // SPI virtual override methods go here + // SPI virtual override methods go here - /// Add primitive to renderer database. - /// - int vAdd( - Primitive* primitive - ); + /// Add primitive to renderer database. + /// + int vAdd( + Primitive* primitive + ); - /// Remove primitive from renderer database. - /// - void vRemove( - int id - ); + /// Remove primitive from renderer database. + /// + void vRemove( + int id + ); - /// Render triangle database. - /// - void vRender(); + /// Render triangle database. + /// + void vRender(); private: - int _maxCount; + int _maxCount; - // GL related parameters + // GL related parameters - GLuint _triBufferId; ///< GL element array buffer id - GLuint _vertexBufferId; ///< GL vertex array buffer id + GLuint _triBufferId; ///< GL element array buffer id + GLuint _vertexBufferId; ///< GL vertex array buffer id - // Book keeping parameters + // Book keeping parameters - int _vertexElementCount; ///< Count of vertices - int _maxVertexElementCount; ///< Max count of vertices + int _vertexElementCount; ///< Count of vertices + int _maxVertexElementCount; ///< Max count of vertices - int _triElementCount; ///< Count of triangles - int _maxTriElementCount; ///< Max count of triangles + int _triElementCount; ///< Count of triangles + int _maxTriElementCount; ///< Max count of triangles - std::map _indexToPrimitiveMap; ///< Associative map between index and primitive - int _primitiveCount; ///< Count of primitives + std::map _indexToPrimitiveMap; ///< Associative map between index and primitive + int _primitiveCount; ///< Count of primitives - Queue _availablePrimitiveIndex; ///< Queue of primitive indices available - Queue _availableVertexElementIndex; ///< Queue of vertex element indices available - Queue _availableTriElementIndex; ///< Queue of triangle element indices available - Queue _deconstructTriElementIndex; ///< Queue of triangle element indices requiring GL update + Queue _availablePrimitiveIndex; ///< Queue of primitive indices available + Queue _availableVertexElementIndex; ///< Queue of vertex element indices available + Queue _availableTriElementIndex; ///< Queue of triangle element indices available + Queue _deconstructTriElementIndex; ///< Queue of triangle element indices requiring GL update - // Statistics parameters, not necessary for proper operation + // Statistics parameters, not necessary for proper operation - int _gpuMemoryUsage; - int _cpuMemoryUsage; + int _gpuMemoryUsage; + int _cpuMemoryUsage; }; diff --git a/interface/src/Queue.h b/interface/src/Queue.h index 777af7e145..8536b9111d 100644 --- a/interface/src/Queue.h +++ b/interface/src/Queue.h @@ -1,10 +1,10 @@ /** - * @file Queue.h - * An efficient FIFO queue featuring lock-free interaction between - * producer and consumer. + * @file Queue.h + * An efficient FIFO queue featuring lock-free interaction between + * producer and consumer. * - * @author: Norman Crafts - * @copyright 2014, All rights reserved. + * @author: Norman Crafts + * @copyright 2014, All rights reserved. */ #ifndef __QUEUE_H__ #define __QUEUE_H__ @@ -14,84 +14,84 @@ #include "Threading.h" /** - * @class Queue + * @class Queue * - * A template based, efficient first-in/first-out queue featuring lock free - * access between producer and consumer. + * A template based, efficient first-in/first-out queue featuring lock free + * access between producer and consumer. */ template < - class Client, // Managed client class - template class ProducerThreadingPolicy = MultiThreaded, - template class ConsumerThreadingPolicy = MultiThreaded, - class ProducerMutexPolicy = Mutex, - class ConsumerMutexPolicy = Mutex + class Client, // Managed client class + template class ProducerThreadingPolicy = MultiThreaded, + template class ConsumerThreadingPolicy = MultiThreaded, + class ProducerMutexPolicy = Mutex, + class ConsumerMutexPolicy = Mutex > class Queue { public: - /** Default constructor - */ - Queue(); + /** Default constructor + */ + Queue(); - ~Queue(); + ~Queue(); - /** Add an object of managed client class to the tail of the queue - */ - void add( - Client item - ); + /** Add an object of managed client class to the tail of the queue + */ + void add( + Client item + ); - /** Remove an object of managed client class from the head of the queue - */ - Client remove(); + /** Remove an object of managed client class from the head of the queue + */ + Client remove(); - /** Peek at an object of managed client class at the head of the queue - * but do not remove it. - */ - Client peek(); + /** Peek at an object of managed client class at the head of the queue + * but do not remove it. + */ + Client peek(); - /** Is the queue empty? - */ - bool isEmpty(); + /** Is the queue empty? + */ + bool isEmpty(); private: - struct __node - { - /** Default node constructor - */ - __node() : - _item(), - _next(0) - {} + struct __node + { + /** Default node constructor + */ + __node() : + _item(), + _next(0) + {} - /** Item injection constructor - */ - __node( - Client item - ) : - _item(item), - _next(0) - {} + /** Item injection constructor + */ + __node( + Client item + ) : + _item(item), + _next(0) + {} - Client _item; - struct __node *_next; - }; + Client _item; + struct __node *_next; + }; - static const int s_cacheLineSize = 64; ///< Cache line size (in bytes) of standard Intel architecture - char pad0[s_cacheLineSize]; ///< Padding to eliminate cache line contention between threads + static const int s_cacheLineSize = 64; ///< Cache line size (in bytes) of standard Intel architecture + char pad0[s_cacheLineSize]; ///< Padding to eliminate cache line contention between threads - ProducerThreadingPolicy _producerGuard; - char pad1[s_cacheLineSize - sizeof(ProducerThreadingPolicy)]; + ProducerThreadingPolicy _producerGuard; + char pad1[s_cacheLineSize - sizeof(ProducerThreadingPolicy)]; - ConsumerThreadingPolicy _consumerGuard; - char pad2[s_cacheLineSize - sizeof(ConsumerThreadingPolicy)]; + ConsumerThreadingPolicy _consumerGuard; + char pad2[s_cacheLineSize - sizeof(ConsumerThreadingPolicy)]; - struct __node *_first; ///< Queue management - char pad3[s_cacheLineSize - sizeof(struct __node *)]; + struct __node *_first; ///< Queue management + char pad3[s_cacheLineSize - sizeof(struct __node *)]; - struct __node *_last; ///< Queue management - char pad4[s_cacheLineSize - sizeof(struct __node *)]; + struct __node *_last; ///< Queue management + char pad4[s_cacheLineSize - sizeof(struct __node *)]; }; @@ -102,171 +102,171 @@ private: template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::Queue() + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::Queue() { - _first = new __node(); - _last = _first; - memset(pad0, 0, sizeof(pad0)); - memset(pad1, 0, sizeof(pad1)); - memset(pad2, 0, sizeof(pad2)); - memset(pad3, 0, sizeof(pad3)); - memset(pad4, 0, sizeof(pad4)); + _first = new __node(); + _last = _first; + memset(pad0, 0, sizeof(pad0)); + memset(pad1, 0, sizeof(pad1)); + memset(pad2, 0, sizeof(pad2)); + memset(pad3, 0, sizeof(pad3)); + memset(pad4, 0, sizeof(pad4)); } template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::~Queue() + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::~Queue() { - AutoLock > lock(_consumerGuard); - while (_first) - { - struct __node *t = _first; - _first = t->_next; - delete t; - } + AutoLock > lock(_consumerGuard); + while (_first) + { + struct __node *t = _first; + _first = t->_next; + delete t; + } } template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > void Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::add( - Client item - ) + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::add( + Client item + ) { - struct __node *n = new __node(item); - AutoLock > lock(_producerGuard); - _last->_next = n; - _last = n; + struct __node *n = new __node(item); + AutoLock > lock(_producerGuard); + _last->_next = n; + _last = n; } template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > Client Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::remove() + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::remove() { - AutoLock > lock(_consumerGuard); - struct __node *next = _first->_next; - if (next) - { - struct __node *first = _first; - Client item = next->_item; - next->_item = 0; - _first = next; - delete first; - return item; - } - return 0; + AutoLock > lock(_consumerGuard); + struct __node *next = _first->_next; + if (next) + { + struct __node *first = _first; + Client item = next->_item; + next->_item = 0; + _first = next; + delete first; + return item; + } + return 0; } template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > Client Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::peek() + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::peek() { - AutoLock > lock(_consumerGuard); - struct __node *next = _first->_next; - if (next) - { - Client item = next->_item; - return item; - } - return 0; + AutoLock > lock(_consumerGuard); + struct __node *next = _first->_next; + if (next) + { + Client item = next->_item; + return item; + } + return 0; } template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > + < + class Client, + template class ProducerThreadingPolicy, + template class ConsumerThreadingPolicy, + class ProducerMutexPolicy, + class ConsumerMutexPolicy + > bool Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::isEmpty() + < + Client, + ProducerThreadingPolicy, + ConsumerThreadingPolicy, + ProducerMutexPolicy, + ConsumerMutexPolicy + >::isEmpty() { - bool empty = true; - AutoLock > lock(_consumerGuard); - struct __node *next = _first->_next; - if (next) - empty = false; + bool empty = true; + AutoLock > lock(_consumerGuard); + struct __node *next = _first->_next; + if (next) + empty = false; - return empty; + return empty; } -#endif // __QUEUE_H__ +#endif // __QUEUE_H__ diff --git a/interface/src/Threading.h b/interface/src/Threading.h index 2684199437..02870fed44 100644 --- a/interface/src/Threading.h +++ b/interface/src/Threading.h @@ -1,46 +1,46 @@ /** - * @file Threading.h - * A delegate pattern to encapsulate threading policy semantics. + * @file Threading.h + * A delegate pattern to encapsulate threading policy semantics. * - * @author: Norman Crafts - * @copyright 2014, All rights reserved. + * @author: Norman Crafts + * @copyright 2014, All rights reserved. */ #ifndef __THREADING_H__ #define __THREADING_H__ /** - * @class SingleThreaded + * @class SingleThreaded */ template < - class MutexPolicy = Mutex ///< Mutex policy + class MutexPolicy = Mutex ///< Mutex policy > class SingleThreaded { public: - void lock(); + void lock(); - void unlock(); + void unlock(); }; /** - * @class MultiThreaded + * @class MultiThreaded */ template < - class MutexPolicy = Mutex ///< Mutex policy + class MutexPolicy = Mutex ///< Mutex policy > class MultiThreaded { public: - void lock(); + void lock(); - void unlock(); + void unlock(); private: - MutexPolicy _mutex; + MutexPolicy _mutex; }; @@ -64,15 +64,15 @@ template inline void MultiThreaded::lock() { - _mutex.lock(); + _mutex.lock(); } template inline void MultiThreaded::unlock() { - _mutex.unlock(); + _mutex.unlock(); } -#endif // __THREADING_H__ +#endif // __THREADING_H__ From 52290266b0613d2b90ddbbe6b1e65487c74f6882 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Fri, 7 Feb 2014 22:11:47 -0500 Subject: [PATCH 04/31] Fixes for style conformance: replace constants with enums --- libraries/octree/src/OctreeElement.h | 1 + libraries/voxels/src/VoxelTreeElement.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 98e4dc9d4e..9e5c62c0c3 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -201,6 +201,7 @@ public: struct HalfSpace { enum { + None = 0x00, Bottom = 0x01, Top = 0x02, Right = 0x04, diff --git a/libraries/voxels/src/VoxelTreeElement.cpp b/libraries/voxels/src/VoxelTreeElement.cpp index aff71584a8..0a577417ec 100644 --- a/libraries/voxels/src/VoxelTreeElement.cpp +++ b/libraries/voxels/src/VoxelTreeElement.cpp @@ -16,8 +16,8 @@ VoxelTreeElement::VoxelTreeElement(unsigned char* octalCode) : OctreeElement(), _primitiveIndex(0), - _exteriorOcclusions(0x3f), - _interiorOcclusions(0) + _exteriorOcclusions(OctreeElement::HalfSpace::All), + _interiorOcclusions(OctreeElement::HalfSpace::None) { init(octalCode); }; From 984110790c3db0586e7c05ba5e2c3df3a4562ceb Mon Sep 17 00:00:00 2001 From: matsukaze Date: Fri, 7 Feb 2014 22:15:25 -0500 Subject: [PATCH 05/31] Added new display mode to show culled faces. More statistics. --- interface/src/VoxelSystem.cpp | 135 +++++++++++++++++----------------- interface/src/VoxelSystem.h | 2 + 2 files changed, 68 insertions(+), 69 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index d128627b42..a90910fe02 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -60,6 +60,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _treeScale(treeScale), _maxVoxels(maxVoxels), _initialized(false), + _showCulledSharedFaces(false), _usePrimitiveRenderer(false), _renderer(0) { @@ -350,8 +351,7 @@ void VoxelSystem::cleanupVoxelMemory() { _writeVoxelShaderData = _readVoxelShaderData = NULL; - } else - if (! _usePrimitiveRenderer) { + } else { // Destroy glBuffers glDeleteBuffers(1, &_vboVerticesID); glDeleteBuffers(1, &_vboColorsID); @@ -373,10 +373,8 @@ void VoxelSystem::cleanupVoxelMemory() { _readColorsArray = NULL; _writeColorsArray = NULL; } - else { - delete _renderer; - _renderer = 0; - } + delete _renderer; + _renderer = 0; delete[] _writeVoxelDirtyArray; delete[] _readVoxelDirtyArray; _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL; @@ -461,8 +459,7 @@ void VoxelSystem::initVoxelMemory() { _readVoxelShaderData = new VoxelShaderVBOData[_maxVoxels]; _memoryUsageRAM += (sizeof(VoxelShaderVBOData) * _maxVoxels); - } else - if (! _usePrimitiveRenderer) { + } else { // Global Normals mode uses a technique of not including normals on any voxel vertices, and instead // rendering the voxel faces in 6 passes that use a global call to glNormal3f() @@ -525,27 +522,7 @@ void VoxelSystem::initVoxelMemory() { _shadowMapProgram.release(); } } - else { - _renderer = new PrimitiveRenderer(_maxVoxels); - // create our simple fragment shader if we're the first system to init - if (!_perlinModulateProgram.isLinked()) { - switchToResourcesParentIfRequired(); - _perlinModulateProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/perlin_modulate.vert"); - _perlinModulateProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/perlin_modulate.frag"); - _perlinModulateProgram.link(); - - _perlinModulateProgram.bind(); - _perlinModulateProgram.setUniformValue("permutationNormalTexture", 0); - _perlinModulateProgram.release(); - - _shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/shadow_map.frag"); - _shadowMapProgram.link(); - - _shadowMapProgram.bind(); - _shadowMapProgram.setUniformValue("shadowMap", 0); - _shadowMapProgram.release(); - } - } + _renderer = new PrimitiveRenderer(_maxVoxels); _initialized = true; @@ -690,12 +667,9 @@ void VoxelSystem::setupNewVoxelsForDrawing() { if (_writeRenderFullVBO) { if (_usePrimitiveRenderer) { - delete _renderer; - _renderer = new PrimitiveRenderer(_maxVoxels); - } - else { - clearFreeBufferIndexes(); + _renderer->release(); } + clearFreeBufferIndexes(); } _voxelsUpdated = newTreeToArrays(_tree->getRoot()); _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean @@ -851,7 +825,8 @@ void VoxelSystem::cleanupRemovedVoxels() { // we also might have VBO slots that have been abandoned, if too many of our VBO slots // are abandonded we want to rerender our full VBOs const float TOO_MANY_ABANDONED_RATIO = 0.5f; - if (!_writeRenderFullVBO && (_abandonedVBOSlots > (_voxelsInWriteArrays * TOO_MANY_ABANDONED_RATIO))) { + if (!_usePrimitiveRenderer && !_writeRenderFullVBO && + (_abandonedVBOSlots > (_voxelsInWriteArrays * TOO_MANY_ABANDONED_RATIO))) { if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { qDebug() << "cleanupRemovedVoxels().. _abandonedVBOSlots [" << _abandonedVBOSlots << "] > TOO_MANY_ABANDONED_RATIO"; @@ -1054,12 +1029,17 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo node->setVoxelSystem(this); } inspectForInteriorOcclusionsOperation(node, 0); - - if (node->getInteriorOcclusions() != OctreeElement::HalfSpace::All) { + unsigned char occlusions; + if (_showCulledSharedFaces) { + occlusions = ~node->getInteriorOcclusions(); + } else { + occlusions = node->getInteriorOcclusions(); + } + if (occlusions != OctreeElement::HalfSpace::All) { Cube* cube = new Cube( startVertex.x, startVertex.y, startVertex.z, voxelScale, color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX], - node->getInteriorOcclusions()); + occlusions); if (cube) { primitiveIndex = _renderer->add(cube); node->setPrimitiveIndex(primitiveIndex); @@ -1491,6 +1471,7 @@ void VoxelSystem::killLocalVoxels() { _tree->eraseAllOctreeElements(); unlockTree(); clearFreeBufferIndexes(); + _renderer->release(); _voxelsInReadArrays = 0; // do we need to do this? setupNewVoxelsForDrawing(); } @@ -1541,7 +1522,7 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, // all faces which are completely covered by four child octants. unsigned char exteriorOcclusionsA = childA->getExteriorOcclusions(); - if (exteriorOcclusionsA == 0) { + if (exteriorOcclusionsA == OctreeElement::HalfSpace::None) { // There is nothing to be done with this child, next... continue; } @@ -1554,7 +1535,7 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, // Get child B's occluding faces unsigned char exteriorOcclusionsB = childB->getExteriorOcclusions(); - if (exteriorOcclusionsB == 0) { + if (exteriorOcclusionsB == OctreeElement::HalfSpace::None) { // There is nothing to be done with this child, next... continue; } @@ -1580,7 +1561,7 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, // Inform the child childA->setInteriorOcclusions(occludedSharedFace[i]); - if (occludedSharedFace[i]) { + if (occludedSharedFace[i] != OctreeElement::HalfSpace::None) { //const glm::vec3& v = voxel->getCorner(); //float s = voxel->getScale(); @@ -1630,7 +1611,7 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, { // Derive the exterior occlusions of the voxel elements from the exclusions // of its children - unsigned char exteriorOcclusions = 0; + unsigned char exteriorOcclusions = OctreeElement::HalfSpace::None; for (int i = 6; --i >= 0; ) { if (exteriorOcclusionsCt[i] == 4) { @@ -1653,7 +1634,7 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, // occupied. Hence, the subtree from this node could be // pruned and replaced by a leaf voxel, if the visible // properties of the children are the same - } else if (exteriorOcclusions) { + } else if (exteriorOcclusions != OctreeElement::HalfSpace::None) { //const glm::vec3& v = voxel->getCorner(); //float s = voxel->getScale(); @@ -1675,11 +1656,11 @@ bool VoxelSystem::clearOcclusionsOperation(OctreeElement* element, void* extraDa voxel->setExteriorOcclusions(OctreeElement::HalfSpace::All); // And the sibling occluders - voxel->setInteriorOcclusions(0); + voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); rc = false; } else { - voxel->setExteriorOcclusions(0); - voxel->setInteriorOcclusions(0); + voxel->setExteriorOcclusions(OctreeElement::HalfSpace::None); + voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); rc = true; } @@ -1690,10 +1671,9 @@ void VoxelSystem::cullSharedFaces() { _nodeCount = 0; if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { - cleanupVoxelMemory(); _useVoxelShader = false; _usePrimitiveRenderer = true; - initVoxelMemory(); + _renderer->release(); clearAllNodesBufferIndex(); lockTree(); _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); @@ -1706,9 +1686,8 @@ void VoxelSystem::cullSharedFaces() { unlockTree(); qDebug("culling shared faces in %d nodes", _nodeCount); } else { - cleanupVoxelMemory(); _usePrimitiveRenderer = false; - initVoxelMemory(); + _renderer->release(); clearAllNodesBufferIndex(); lockTree(); _tree->recurseTreeWithOperation(clearOcclusionsOperation); @@ -1723,6 +1702,18 @@ void VoxelSystem::cullSharedFaces() { } +void VoxelSystem::showCulledSharedFaces() { + + if (Menu::getInstance()->isOptionChecked(MenuOption::ShowCulledSharedFaces)) { + _showCulledSharedFaces = true; + } else { + _showCulledSharedFaces = false; + } + if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { + cullSharedFaces(); + } +} + bool VoxelSystem::forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData) { _nodeCount++; element->setDirtyBit(); @@ -2650,31 +2641,37 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n", args.totalNodes, args.leafNodes, args.dirtyNodes, args.coloredNodes, args.shouldRenderNodes); - qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld", debug::valueOf(_voxelsDirty), - _voxelsInWriteArrays, minDirty, maxDirty); + if (!_usePrimitiveRenderer) { + qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld", debug::valueOf(_voxelsDirty), + _voxelsInWriteArrays, minDirty, maxDirty); - qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld", - args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex, args.nodesInVBONotShouldRender); + qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld", + args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex, args.nodesInVBONotShouldRender); - qDebug(" inPrimitiveRenderer %ld \n completely culled %ld \n", - args.nodesInPrimitiveRenderer, args.culledLeafNodes); + qDebug(" memory usage %ld \n gpu memory usage %ld \n", _memoryUsageRAM, _memoryUsageVBO); - glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN; - glBufferIndex maxInVBO = 0; + glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN; + glBufferIndex maxInVBO = 0; - for (glBufferIndex i = 0; i < _maxVoxels; i++) { - if (args.hasIndexFound[i]) { - minInVBO = std::min(minInVBO,i); - maxInVBO = std::max(maxInVBO,i); + for (glBufferIndex i = 0; i < _maxVoxels; i++) { + if (args.hasIndexFound[i]) { + minInVBO = std::min(minInVBO,i); + maxInVBO = std::max(maxInVBO,i); + } } + + qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld", + minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays); + + qDebug(" _freeIndexes.size()=%ld", + _freeIndexes.size()); + } else { + qDebug(" PrimitiveRenderer nodes %ld \n completely culled nodes %ld \n", + args.nodesInPrimitiveRenderer, args.culledLeafNodes); + + qDebug(" memory usage %ld \n gpu memory usage %ld \n", + _renderer->getMemoryUsage(), _renderer->getMemoryUsageGPU()); } - - qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld", - minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays); - - qDebug(" _freeIndexes.size()=%ld", - _freeIndexes.size()); - qDebug("DONE WITH Local Voxel Tree Statistics >>>>>>>>>>>>"); } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index ee8c28178e..e9f3a0ca8e 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -140,6 +140,7 @@ public slots: void forceRedrawEntireTree(); void clearAllNodesBufferIndex(); void cullSharedFaces(); + void showCulledSharedFaces(); void cancelImport(); @@ -315,6 +316,7 @@ private: void lockTree(); void unlockTree(); + bool _showCulledSharedFaces; ///< Flag visibility of culled faces bool _usePrimitiveRenderer; ///< Flag primitive renderer for use PrimitiveRenderer* _renderer; ///< Voxel renderer From f15ddff7e059d3596b9550f50d1342f606f09680 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Fri, 7 Feb 2014 22:44:53 -0500 Subject: [PATCH 06/31] Added new display mode to show culled faces. --- interface/src/Menu.cpp | 7 +++++++ interface/src/Menu.h | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6c8bd8bfeb..d10ad66741 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -445,6 +445,13 @@ Menu::Menu() : appInstance->getVoxels(), SLOT(cullSharedFaces())); + addCheckableActionToQMenuAndActionHash(renderDebugMenu, + MenuOption::ShowCulledSharedFaces, + Qt::CTRL | Qt::SHIFT | Qt::Key_X, + false, + appInstance->getVoxels(), + SLOT(showCulledSharedFaces())); + addDisabledActionAndSeparator(renderDebugMenu, "Coverage Maps"); addActionToQMenuAndActionHash(renderDebugMenu, MenuOption::FalseColorOccluded, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 13a9352d96..7095cd029f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -169,7 +169,7 @@ namespace MenuOption { const QString CopyVoxels = "Copy"; const QString CoverageMap = "Render Coverage Map"; const QString CoverageMapV2 = "Render Coverage Map V2"; - const QString CullSharedFaces = "Cull shared faces"; + const QString CullSharedFaces = "Cull Shared Voxel Faces"; const QString CutVoxels = "Cut"; const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DecreaseVoxelSize = "Decrease Voxel Size"; @@ -249,6 +249,7 @@ namespace MenuOption { const QString Shadows = "Shadows"; const QString SettingsExport = "Export Settings"; const QString ShowAllLocalVoxels = "Show All Local Voxels"; + const QString ShowCulledSharedFaces = "Show Culled Shared Voxel Faces"; const QString ShowTrueColors = "Show TRUE Colors"; const QString VoxelDrumming = "Voxel Drumming"; const QString PlaySlaps = "Play Slaps"; From ab0b7bba00ba922280724a81a63bc6852dae989f Mon Sep 17 00:00:00 2001 From: matsukaze Date: Fri, 7 Feb 2014 22:52:08 -0500 Subject: [PATCH 07/31] Fixes for style conformance: tabs to spaces --- interface/src/Menu.cpp | 12 ++++---- libraries/octree/src/OctreeElement.h | 22 +++++++-------- libraries/voxels/src/VoxelTreeElement.cpp | 8 +++--- libraries/voxels/src/VoxelTreeElement.h | 34 +++++++++++------------ 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d10ad66741..e27704fc30 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -439,16 +439,16 @@ Menu::Menu() : SLOT(trueColorize())); addCheckableActionToQMenuAndActionHash(renderDebugMenu, - MenuOption::CullSharedFaces, - Qt::CTRL | Qt::SHIFT | Qt::Key_C, - false, + MenuOption::CullSharedFaces, + Qt::CTRL | Qt::SHIFT | Qt::Key_C, + false, appInstance->getVoxels(), SLOT(cullSharedFaces())); addCheckableActionToQMenuAndActionHash(renderDebugMenu, - MenuOption::ShowCulledSharedFaces, - Qt::CTRL | Qt::SHIFT | Qt::Key_X, - false, + MenuOption::ShowCulledSharedFaces, + Qt::CTRL | Qt::SHIFT | Qt::Key_X, + false, appInstance->getVoxels(), SLOT(showCulledSharedFaces())); diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 9e5c62c0c3..1785307696 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -199,18 +199,18 @@ public: CHILD_UNKNOWN = -1 }; - struct HalfSpace { - enum { + struct HalfSpace { + enum { None = 0x00, - Bottom = 0x01, - Top = 0x02, - Right = 0x04, - Left = 0x08, - Near = 0x10, - Far = 0x20, - All = 0x3f, - }; - }; + Bottom = 0x01, + Top = 0x02, + Right = 0x04, + Left = 0x08, + Near = 0x10, + Far = 0x20, + All = 0x3f, + }; + }; OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); diff --git a/libraries/voxels/src/VoxelTreeElement.cpp b/libraries/voxels/src/VoxelTreeElement.cpp index 0a577417ec..4470c47b5e 100644 --- a/libraries/voxels/src/VoxelTreeElement.cpp +++ b/libraries/voxels/src/VoxelTreeElement.cpp @@ -14,10 +14,10 @@ #include "VoxelTree.h" VoxelTreeElement::VoxelTreeElement(unsigned char* octalCode) : - OctreeElement(), - _primitiveIndex(0), - _exteriorOcclusions(OctreeElement::HalfSpace::All), - _interiorOcclusions(OctreeElement::HalfSpace::None) + OctreeElement(), + _primitiveIndex(0), + _exteriorOcclusions(OctreeElement::HalfSpace::All), + _interiorOcclusions(OctreeElement::HalfSpace::None) { init(octalCode); }; diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h index a3c112fcde..15ee5c7c76 100644 --- a/libraries/voxels/src/VoxelTreeElement.h +++ b/libraries/voxels/src/VoxelTreeElement.h @@ -71,10 +71,10 @@ public: void setDensity(float density) { _density = density; } float getDensity() const { return _density; } - void setInteriorOcclusions(unsigned char interiorExclusions); - void setExteriorOcclusions(unsigned char exteriorOcclusions); - unsigned char getExteriorOcclusions() const; - unsigned char getInteriorOcclusions() const; + void setInteriorOcclusions(unsigned char interiorExclusions); + void setExteriorOcclusions(unsigned char exteriorOcclusions); + unsigned char getExteriorOcclusions() const; + unsigned char getInteriorOcclusions() const; // type safe versions of OctreeElement methods VoxelTreeElement* getChildAtIndex(int childIndex) { return (VoxelTreeElement*)OctreeElement::getChildAtIndex(childIndex); } @@ -98,31 +98,31 @@ protected: nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes private: - int _primitiveIndex; - unsigned char _exteriorOcclusions; /// exterior shared partition boundaries that are completely occupied - unsigned char _interiorOcclusions; /// interior shared partition boundaries with siblings + int _primitiveIndex; ///< Unique identifier given by PrimitiveRenderer + unsigned char _exteriorOcclusions; ///< Exterior shared partition boundaries that are completely occupied + unsigned char _interiorOcclusions; ///< Interior shared partition boundaries with siblings }; inline void VoxelTreeElement::setExteriorOcclusions(unsigned char exteriorOcclusions) { - if (_exteriorOcclusions != exteriorOcclusions) { - _exteriorOcclusions = exteriorOcclusions; - setDirtyBit(); - } + if (_exteriorOcclusions != exteriorOcclusions) { + _exteriorOcclusions = exteriorOcclusions; + setDirtyBit(); + } } inline void VoxelTreeElement::setInteriorOcclusions(unsigned char interiorOcclusions) { - if (_interiorOcclusions != interiorOcclusions) { - _interiorOcclusions = interiorOcclusions; - setDirtyBit(); - } + if (_interiorOcclusions != interiorOcclusions) { + _interiorOcclusions = interiorOcclusions; + setDirtyBit(); + } } inline unsigned char VoxelTreeElement::getInteriorOcclusions() const { - return _interiorOcclusions; + return _interiorOcclusions; } inline unsigned char VoxelTreeElement::getExteriorOcclusions() const { - return _exteriorOcclusions; + return _exteriorOcclusions; } #endif /* defined(__hifi__VoxelTreeElement__) */ From 61c48c525c116493231ea48cac6ad5b82ade4baa Mon Sep 17 00:00:00 2001 From: matsukaze Date: Fri, 7 Feb 2014 22:55:03 -0500 Subject: [PATCH 08/31] Fixes for style conformance: replace stl containers with Qt --- interface/src/PrimitiveRenderer.cpp | 236 ++++++++++++++++------------ interface/src/PrimitiveRenderer.h | 84 ++++++++-- 2 files changed, 207 insertions(+), 113 deletions(-) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index 05c0c9444a..2f1ab1fd05 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -5,6 +5,9 @@ * @author: Norman Crafts * @copyright 2014, High Fidelity, Inc. All rights reserved. */ + +#include + #include "InterfaceConfig.h" #include "OctreeElement.h" #include "PrimitiveRenderer.h" @@ -33,6 +36,10 @@ void Primitive::releaseVertexElements() { vReleaseVertexElements(); } +int Primitive::getMemoryUsage() { + return vGetMemoryUsage(); +} + Cube::Cube( float x, @@ -43,7 +50,8 @@ Cube::Cube( unsigned char g, unsigned char b, unsigned char faceExclusions - ) { + ) : + _cpuMemoryUsage(0) { initialize(x, y, z, s, r, g, b, faceExclusions); } @@ -125,6 +133,8 @@ void Cube::initializeVertices( // Add vertex element to list _vertices.push_back(v); + _cpuMemoryUsage += sizeof(VertexElement); + _cpuMemoryUsage += sizeof(VertexElement*); } } } @@ -138,6 +148,7 @@ void Cube::terminateVertices() { for ( ; it != end; ++it) { delete *it; } + _cpuMemoryUsage -= _vertices.size() * (sizeof(VertexElement) + sizeof(VertexElement*)); _vertices.clear(); } @@ -171,6 +182,8 @@ void Cube::initializeTris( // Add tri element to list _tris.push_back(tri); + _cpuMemoryUsage += sizeof(TriElement); + _cpuMemoryUsage += sizeof(TriElement*); } // Now store triangle ACD @@ -182,6 +195,8 @@ void Cube::initializeTris( // Add tri element to list _tris.push_back(tri); + _cpuMemoryUsage += sizeof(TriElement); + _cpuMemoryUsage += sizeof(TriElement*); } } } @@ -195,6 +210,7 @@ void Cube::terminateTris() { for ( ; it != end; ++it) { delete *it; } + _cpuMemoryUsage -= _tris.size() * (sizeof(TriElement) + sizeof(TriElement*)); _tris.clear(); } @@ -214,6 +230,10 @@ void Cube::vReleaseVertexElements() { terminateVertices(); } +int Cube::vGetMemoryUsage() { + return _cpuMemoryUsage; +} + unsigned char Cube::_sFaceIndexToHalfSpaceMask[6] = { OctreeElement::HalfSpace::Bottom, OctreeElement::HalfSpace::Top, @@ -223,10 +243,8 @@ unsigned char Cube::_sFaceIndexToHalfSpaceMask[6] = { OctreeElement::HalfSpace::Far, }; -#define CW_CONSTRUCTION -#ifdef CW_CONSTRUCTION // Construction vectors ordered such that the vertices of each face are -// CW in a right-handed coordinate system with B-L-N at 0,0,0. +// clockwise in a right-handed coordinate system with B-L-N at 0,0,0. float Cube::_sVertexIndexToConstructionVector[24][3] = { // Bottom { 0,0,0 }, @@ -259,42 +277,6 @@ float Cube::_sVertexIndexToConstructionVector[24][3] = { { 1,1,1 }, { 0,1,1 }, }; -#else // CW_CONSTRUCTION -// Construction vectors ordered such that the vertices of each face are -// CCW in a right-handed coordinate system with B-L-N at 0,0,0. -float Cube::_sVertexIndexToConstructionVector[24][3] = { - // Bottom - { 0,0,0 }, - { 0,0,1 }, - { 1,0,1 }, - { 1,0,0 }, - // Top - { 0,1,0 }, - { 1,1,0 }, - { 1,1,1 }, - { 0,1,1 }, - // Right - { 1,0,0 }, - { 1,0,1 }, - { 1,1,1 }, - { 1,1,0 }, - // Left - { 0,0,0 }, - { 0,1,0 }, - { 0,1,1 }, - { 0,0,1 }, - // Near - { 0,0,0 }, - { 1,0,0 }, - { 1,1,0 }, - { 0,1,0 }, - // Far - { 0,0,1 }, - { 0,1,1 }, - { 1,1,1 }, - { 1,0,1 }, -}; -#endif // Normals for a right-handed coordinate system float Cube::_sVertexIndexToNormalVector[6][3] = { @@ -325,18 +307,30 @@ void Renderer::remove( vRemove(id); } +void Renderer::release() { + vRelease(); +} + void Renderer::render() { vRender(); } +int Renderer::getMemoryUsage() { + return vGetMemoryUsage(); +} + +int Renderer::getMemoryUsageGPU() { + return vGetMemoryUsageGPU(); +} + PrimitiveRenderer::PrimitiveRenderer( int maxCount ) : _maxCount(maxCount), _vertexElementCount(0), - _maxVertexElementCount(maxCount), + _maxVertexElementCount(0), _triElementCount(0), - _maxTriElementCount(maxCount), + _maxTriElementCount(0), _primitiveCount(0), _triBufferId(0), @@ -366,7 +360,8 @@ void PrimitiveRenderer::initializeGL() { glGenBuffers(1, &_vertexBufferId); // Set up the element array buffer containing the index ids - int size = _maxCount * sizeof(GLint) * 3; + _maxTriElementCount = _maxCount * 3 * 2; + int size = _maxTriElementCount * sizeof(GLint); _gpuMemoryUsage += size; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); @@ -376,7 +371,8 @@ void PrimitiveRenderer::initializeGL() { // Set up the array buffer in the form of array of structures // I chose AOS because it maximizes the amount of data tranferred // by a single glBufferSubData call. - size = _maxCount * sizeof(VertexElement); + _maxVertexElementCount = _maxCount * 4; + size = _maxVertexElementCount * sizeof(VertexElement); _gpuMemoryUsage += size; glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); @@ -429,60 +425,22 @@ void PrimitiveRenderer::terminateBookkeeping() { while (_deconstructTriElementIndex.remove() != 0) ; - std::map::iterator it = _indexToPrimitiveMap.begin(); - std::map::iterator end = _indexToPrimitiveMap.end(); + _vertexElementCount = 0; + _triElementCount = 0; + + QMap::iterator it = _indexToPrimitiveMap.begin(); + QMap::iterator end = _indexToPrimitiveMap.end(); for ( ; it != end; ++it) { - Primitive *primitive = it->second; - delete primitive; - } -} - -int PrimitiveRenderer::vAdd( - Primitive* primitive - ) { - - int index = getAvailablePrimitiveIndex(); - if (index != 0) { - try { - // Take ownership of primitive, including responsibility - // for destruction - _indexToPrimitiveMap[index] = primitive; - constructElements(primitive); - - // No need to keep an extra copy of the vertices - primitive->releaseVertexElements(); - } catch(...) { - // STL failed, recycle the index - _availablePrimitiveIndex.add(index); - index = 0; + Primitive* primitive = it.value(); + if (primitive) { + _cpuMemoryUsage -= primitive->getMemoryUsage(); + delete primitive; } } - return index; -} -void PrimitiveRenderer::vRemove( - int index - ) { - - try { - - // Locate the primitive by id in the associative map - std::map::iterator it = _indexToPrimitiveMap.find(index); - if (it != _indexToPrimitiveMap.end()) { - Primitive *primitive = it->second; - if (primitive) { - _indexToPrimitiveMap[index] = 0; - deconstructElements(primitive); - _availablePrimitiveIndex.add(index); - } - // Not necessary to remove the item from the associative map, because - // the index is going to be re-used, but if you want to... uncomment the following: - //_indexToPrimitiveMap.erase(it); - } - } catch(...) { - // STL failed - } + _cpuMemoryUsage -= _indexToPrimitiveMap.size() * sizeof(Primitive*); + _indexToPrimitiveMap.clear(); } void PrimitiveRenderer::constructElements( @@ -491,8 +449,8 @@ void PrimitiveRenderer::constructElements( // Load vertex elements VertexElementIndexList& vertexElementIndexList = primitive->vertexElementIndices(); + VertexElementList const & vertices = primitive->vertexElements(); { - VertexElementList const & vertices = primitive->vertexElements(); VertexElementList::const_iterator it = vertices.begin(); VertexElementList::const_iterator end = vertices.end(); @@ -507,7 +465,7 @@ void PrimitiveRenderer::constructElements( } // Load tri elements - { + if (vertexElementIndexList.size() == vertices.size()) { TriElementList& tris = primitive->triElements(); TriElementList::iterator it = tris.begin(); TriElementList::iterator end = tris.end(); @@ -530,6 +488,8 @@ void PrimitiveRenderer::constructElements( transferTriElement(index, tri->indices); } } + } else { + // TODO: failure mode } } @@ -647,16 +607,91 @@ void PrimitiveRenderer::transferTriElement( glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } +int PrimitiveRenderer::vAdd( + Primitive* primitive + ) { + + QMutexLocker lock(&_guard); + int index = getAvailablePrimitiveIndex(); + if (index != 0) { + try { + // Take ownership of primitive, including responsibility + // for destruction + _indexToPrimitiveMap[index] = primitive; + _constructPrimitiveIndex.add(index); + _cpuMemoryUsage += primitive->getMemoryUsage(); + _cpuMemoryUsage += sizeof(Primitive*); + } catch(...) { + // STL failed, recycle the index + _availablePrimitiveIndex.add(index); + index = 0; + } + } + return index; +} + +void PrimitiveRenderer::vRemove( + int index + ) { + + try { + QMutexLocker lock(&_guard); + + // Locate and remove the primitive by id in the associative map + Primitive* primitive = _indexToPrimitiveMap.take(index); + if (primitive) { + _cpuMemoryUsage -= primitive->getMemoryUsage(); + deconstructElements(primitive); + _availablePrimitiveIndex.add(index); + } + } catch(...) { + // STL failed + } +} + +void PrimitiveRenderer::vRelease() { + + QMutexLocker lock(&_guard); + terminateBookkeeping(); +#if 0 + QMap::iterator it = _indexToPrimitiveMap.begin(); + QMap::iterator end = _indexToPrimitiveMap.end(); + + for ( ; it != end; ++it) { + Primitive* primitive = it->second; + if (primitive) { + it->second = 0; + deconstructElements(primitive); + _availablePrimitiveIndex.add(it->first); + } + } +#endif +} + void PrimitiveRenderer::vRender() { + int id; + + QMutexLocker lock(&_guard); // Now would be an appropriate time to set the element array buffer ids // scheduled for deconstruction to the degenerate case. - int id; while ((id = _deconstructTriElementIndex.remove()) != 0) { deconstructTriElement(id); _availableTriElementIndex.add(id); } + while ((id = _constructPrimitiveIndex.remove()) != 0) { + Primitive* primitive = _indexToPrimitiveMap[id]; + if (primitive) { + constructElements(primitive); + + // No need to keep an extra copy of the vertices + _cpuMemoryUsage -= primitive->getMemoryUsage(); + primitive->releaseVertexElements(); + _cpuMemoryUsage += primitive->getMemoryUsage(); + } + } + // The application uses clockwise winding for the definition of front face, but I // arbitrarily chose counter-clockwise (that is the gl default) to construct the triangulation // so... @@ -683,8 +718,13 @@ void PrimitiveRenderer::vRender() { glDisable(GL_CULL_FACE); - // TODO: does the interface ever change the winding order? - //glFrontFace(GL_CW); err = glGetError(); } +int PrimitiveRenderer::vGetMemoryUsage() { + return _cpuMemoryUsage; +} + +int PrimitiveRenderer::vGetMemoryUsageGPU() { + return _gpuMemoryUsage; +} \ No newline at end of file diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/PrimitiveRenderer.h index f2ebfe23f4..0568d3bb0a 100644 --- a/interface/src/PrimitiveRenderer.h +++ b/interface/src/PrimitiveRenderer.h @@ -9,7 +9,9 @@ #ifndef __interface__PrimitiveRenderer__ #define __interface__PrimitiveRenderer__ -#include +#include +#include + #include "Queue.h" /// Vertex element structure. @@ -46,9 +48,9 @@ typedef } TriElement; -typedef std::vector > VertexElementList; -typedef std::vector > VertexElementIndexList; -typedef std::vector > TriElementList; +typedef QVector VertexElementList; +typedef QVector VertexElementIndexList; +typedef QVector TriElementList; /// /// @class Primitive @@ -81,6 +83,10 @@ public: /// void releaseVertexElements(); + /// Get memory usage. + /// + int getMemoryUsage(); + protected: /// Default constructor prohibited to API user, restricted to service implementer. /// @@ -117,6 +123,10 @@ private: /// virtual void vReleaseVertexElements() = 0; + /// Get memory usage. + /// + virtual int vGetMemoryUsage() = 0; + }; @@ -186,12 +196,14 @@ private: VertexElementIndexList& vVertexElementIndices(); TriElementList& vTriElements(); void vReleaseVertexElements(); - + int vGetMemoryUsage(); private: VertexElementList _vertices; ///< Vertex element list - VertexElementIndexList _vertexIndices; ///< Vertex element index list - TriElementList _tris; ///< Tri element list + VertexElementIndexList _vertexIndices; ///< Vertex element index list + TriElementList _tris; ///< Tri element list + + int _cpuMemoryUsage; ///< Memory allocation of object static const int _sNumFacesPerCube = 6; static const int _sNumVerticesPerCube = 24; @@ -225,12 +237,24 @@ public: int id ///< Primitive id ); + /// Clear all primitives from renderer database + /// + void release(); + /// Render primitive database. /// The render method assumes appropriate GL context and state has /// already been provided for /// void render(); + /// Get memory usage. + /// + int getMemoryUsage(); + + /// Get GPU memory usage. + /// + int getMemoryUsageGPU(); + protected: /// Default constructor prohibited to API user, restricted to service implementer. /// @@ -261,11 +285,26 @@ private: int id ///< Primitive id ) = 0; + /// Clear all primitives from renderer database + /// Service implementer to provide private override for this method + /// in derived class + /// + virtual void vRelease() = 0; + /// Render primitive database. /// Service implementer to provide private virtual override for this method /// in derived class /// virtual void vRender() = 0; + + /// Get memory usage. + /// + virtual int vGetMemoryUsage() = 0; + + /// Get GPU memory usage. + /// + virtual int vGetMemoryUsageGPU() = 0; + }; /// @@ -373,10 +412,22 @@ private: int id ); + /// Clear all primitives from renderer database + /// + void vRelease(); + /// Render triangle database. /// void vRender(); + /// Get memory usage. + /// + int vGetMemoryUsage(); + + /// Get gpu memory usage. + /// + int vGetMemoryUsageGPU(); + private: int _maxCount; @@ -384,23 +435,26 @@ private: // GL related parameters GLuint _triBufferId; ///< GL element array buffer id - GLuint _vertexBufferId; ///< GL vertex array buffer id + GLuint _vertexBufferId; ///< GL vertex array buffer id // Book keeping parameters int _vertexElementCount; ///< Count of vertices - int _maxVertexElementCount; ///< Max count of vertices + int _maxVertexElementCount; ///< Max count of vertices - int _triElementCount; ///< Count of triangles + int _triElementCount; ///< Count of triangles int _maxTriElementCount; ///< Max count of triangles - std::map _indexToPrimitiveMap; ///< Associative map between index and primitive + QMap _indexToPrimitiveMap; ///< Associative map between index and primitive int _primitiveCount; ///< Count of primitives - Queue _availablePrimitiveIndex; ///< Queue of primitive indices available - Queue _availableVertexElementIndex; ///< Queue of vertex element indices available - Queue _availableTriElementIndex; ///< Queue of triangle element indices available - Queue _deconstructTriElementIndex; ///< Queue of triangle element indices requiring GL update + Queue _availablePrimitiveIndex; ///< Queue of primitive indices available + Queue _availableVertexElementIndex; ///< Queue of vertex element indices available + Queue _availableTriElementIndex; ///< Queue of triangle element indices available + Queue _deconstructTriElementIndex; ///< Queue of triangle element indices requiring deletion from GL + Queue _constructPrimitiveIndex; ///< Queue of primitives requiring addition to GL + + QMutex _guard; // Statistics parameters, not necessary for proper operation From 18e219b5c0fe321e32d7bae1ea4debc8f8ad92fb Mon Sep 17 00:00:00 2001 From: matsukaze Date: Sat, 8 Feb 2014 09:06:14 -0500 Subject: [PATCH 09/31] Fixes for style conformance: tabs to spaces --- interface/src/VoxelSystem.cpp | 764 +++++++++++++++++----------------- interface/src/VoxelSystem.h | 11 +- 2 files changed, 388 insertions(+), 387 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index a90910fe02..82f72bfb4d 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -61,8 +61,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _maxVoxels(maxVoxels), _initialized(false), _showCulledSharedFaces(false), - _usePrimitiveRenderer(false), - _renderer(0) { + _usePrimitiveRenderer(false), + _renderer(0) { _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; _writeRenderFullVBO = true; @@ -215,16 +215,16 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) { } } if (!inList) { - // make the index available for next node that needs to be drawn - _freeIndexLock.lock(); - _freeIndexes.push_back(index); - _freeIndexLock.unlock(); + // make the index available for next node that needs to be drawn + _freeIndexLock.lock(); + _freeIndexes.push_back(index); + _freeIndexLock.unlock(); - // make the VBO slot "invisible" in case this slot is not used - const glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); - const float voxelScale = 0; - const nodeColor BLACK = {0, 0, 0, 0}; - updateArraysDetails(index, startVertex, voxelScale, BLACK); + // make the VBO slot "invisible" in case this slot is not used + const glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); + const float voxelScale = 0; + const nodeColor BLACK = {0, 0, 0, 0}; + updateArraysDetails(index, startVertex, voxelScale, BLACK); } } @@ -254,7 +254,7 @@ VoxelSystem::~VoxelSystem() { cleanupVoxelMemory(); delete _tree; - _renderer = 0; + _renderer = 0; } void VoxelSystem::setMaxVoxels(int maxVoxels) { @@ -263,12 +263,12 @@ void VoxelSystem::setMaxVoxels(int maxVoxels) { } bool wasInitialized = _initialized; if (wasInitialized) { - clearAllNodesBufferIndex(); - cleanupVoxelMemory(); + clearAllNodesBufferIndex(); + cleanupVoxelMemory(); } _maxVoxels = maxVoxels; if (wasInitialized) { - initVoxelMemory(); + initVoxelMemory(); } if (wasInitialized) { forceRedrawEntireTree(); @@ -286,7 +286,7 @@ void VoxelSystem::setUseVoxelShader(bool useVoxelShader) { cleanupVoxelMemory(); } _useVoxelShader = useVoxelShader; - _usePrimitiveRenderer = false; + _usePrimitiveRenderer = false; if (wasInitialized) { initVoxelMemory(); } @@ -373,8 +373,8 @@ void VoxelSystem::cleanupVoxelMemory() { _readColorsArray = NULL; _writeColorsArray = NULL; } - delete _renderer; - _renderer = 0; + delete _renderer; + _renderer = 0; delete[] _writeVoxelDirtyArray; delete[] _readVoxelDirtyArray; _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL; @@ -522,7 +522,7 @@ void VoxelSystem::initVoxelMemory() { _shadowMapProgram.release(); } } - _renderer = new PrimitiveRenderer(_maxVoxels); + _renderer = new PrimitiveRenderer(_maxVoxels); _initialized = true; @@ -666,10 +666,10 @@ void VoxelSystem::setupNewVoxelsForDrawing() { _callsToTreesToArrays++; if (_writeRenderFullVBO) { - if (_usePrimitiveRenderer) { - _renderer->release(); - } - clearFreeBufferIndexes(); + if (_usePrimitiveRenderer) { + _renderer->release(); + } + clearFreeBufferIndexes(); } _voxelsUpdated = newTreeToArrays(_tree->getRoot()); _tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean @@ -685,24 +685,24 @@ void VoxelSystem::setupNewVoxelsForDrawing() { _voxelsUpdated = 0; } - if (_usePrimitiveRenderer) { - if (_voxelsUpdated) { - _voxelsDirty=true; - } - } - else { - // lock on the buffer write lock so we can't modify the data when the GPU is reading it - _bufferWriteLock.lock(); + if (_usePrimitiveRenderer) { + if (_voxelsUpdated) { + _voxelsDirty=true; + } + } + else { + // lock on the buffer write lock so we can't modify the data when the GPU is reading it + _bufferWriteLock.lock(); - if (_voxelsUpdated) { - _voxelsDirty=true; - } + if (_voxelsUpdated) { + _voxelsDirty=true; + } - // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated - copyWrittenDataToReadArrays(didWriteFullVBO); + // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated + copyWrittenDataToReadArrays(didWriteFullVBO); - _bufferWriteLock.unlock(); - } + _bufferWriteLock.unlock(); + } quint64 end = usecTimestampNow(); int elapsedmsec = (end - start) / 1000; @@ -730,28 +730,28 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { return; // bail early, it hasn't been long enough since the last time we ran } - if (_usePrimitiveRenderer) { - _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty - _voxelsUpdated = 0; - } - else { - // lock on the buffer write lock so we can't modify the data when the GPU is reading it - { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" ); - _bufferWriteLock.lock(); - } + if (_usePrimitiveRenderer) { + _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty + _voxelsUpdated = 0; + } + else { + // lock on the buffer write lock so we can't modify the data when the GPU is reading it + { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "setupNewVoxelsForDrawingSingleNode()... _bufferWriteLock.lock();" ); + _bufferWriteLock.lock(); + } - _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty + _voxelsDirty = true; // if we got this far, then we can assume some voxels are dirty - // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated - copyWrittenDataToReadArrays(_writeRenderFullVBO); + // copy the newly written data to the arrays designated for reading, only does something if _voxelsDirty && _voxelsUpdated + copyWrittenDataToReadArrays(_writeRenderFullVBO); - // after... - _voxelsUpdated = 0; + // after... + _voxelsUpdated = 0; - _bufferWriteLock.unlock(); - } + _bufferWriteLock.unlock(); + } quint64 end = usecTimestampNow(); int elapsedmsec = (end - start) / 1000; _setupNewVoxelsForDrawingLastFinished = end; @@ -972,24 +972,24 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelTreeElement* node) { return 0; } - if (_usePrimitiveRenderer) { - int primitiveIndex = node->getPrimitiveIndex(); - if (primitiveIndex) { - _renderer->remove(primitiveIndex); - node->setPrimitiveIndex(0); - return 1; - } - } - else { - // if the node is not in the VBOs then we have nothing to do! - if (node->isKnownBufferIndex()) { - // If this node has not yet been written to the array, then add it to the end of the array. - glBufferIndex nodeIndex = node->getBufferIndex(); - node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - freeBufferIndex(nodeIndex); // NOTE: This will make the node invisible! - return 1; // updated! - } - } + if (_usePrimitiveRenderer) { + int primitiveIndex = node->getPrimitiveIndex(); + if (primitiveIndex) { + _renderer->remove(primitiveIndex); + node->setPrimitiveIndex(0); + return 1; + } + } + else { + // if the node is not in the VBOs then we have nothing to do! + if (node->isKnownBufferIndex()) { + // If this node has not yet been written to the array, then add it to the end of the array. + glBufferIndex nodeIndex = node->getBufferIndex(); + node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); + freeBufferIndex(nodeIndex); // NOTE: This will make the node invisible! + return 1; // updated! + } + } return 0; // not-updated } @@ -1016,48 +1016,48 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo if (forceDraw || node->isDirty()) { // If we're should render, use our legit location and scale, if (node->getShouldRender()) { - glm::vec3 startVertex = node->getCorner(); - float voxelScale = node->getScale(); - nodeColor const & color = node->getColor(); + glm::vec3 startVertex = node->getCorner(); + float voxelScale = node->getScale(); + nodeColor const & color = node->getColor(); - if (_usePrimitiveRenderer) { - int primitiveIndex = node->getPrimitiveIndex(); - if (primitiveIndex) { - _renderer->remove(primitiveIndex); - node->setPrimitiveIndex(0); - } else { - node->setVoxelSystem(this); - } - inspectForInteriorOcclusionsOperation(node, 0); + if (_usePrimitiveRenderer) { + int primitiveIndex = node->getPrimitiveIndex(); + if (primitiveIndex) { + _renderer->remove(primitiveIndex); + node->setPrimitiveIndex(0); + } else { + node->setVoxelSystem(this); + } + inspectForInteriorOcclusionsOperation(node, 0); unsigned char occlusions; if (_showCulledSharedFaces) { occlusions = ~node->getInteriorOcclusions(); } else { occlusions = node->getInteriorOcclusions(); } - if (occlusions != OctreeElement::HalfSpace::All) { - Cube* cube = new Cube( - startVertex.x, startVertex.y, startVertex.z, voxelScale, - color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX], - occlusions); - if (cube) { - primitiveIndex = _renderer->add(cube); - node->setPrimitiveIndex(primitiveIndex); - } - } - } else { - glBufferIndex nodeIndex = GLBUFFER_INDEX_UNKNOWN; - if (reuseIndex && node->isKnownBufferIndex()) { - nodeIndex = node->getBufferIndex(); - } else { - nodeIndex = getNextBufferIndex(); - node->setBufferIndex(nodeIndex); - node->setVoxelSystem(this); - } - // populate the array with points for the 8 vertices and RGB color for each added vertex - updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); - } - return 1; // updated! + if (occlusions != OctreeElement::HalfSpace::All) { + Cube* cube = new Cube( + startVertex.x, startVertex.y, startVertex.z, voxelScale, + color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX], + occlusions); + if (cube) { + primitiveIndex = _renderer->add(cube); + node->setPrimitiveIndex(primitiveIndex); + } + } + } else { + glBufferIndex nodeIndex = GLBUFFER_INDEX_UNKNOWN; + if (reuseIndex && node->isKnownBufferIndex()) { + nodeIndex = node->getBufferIndex(); + } else { + nodeIndex = getNextBufferIndex(); + node->setBufferIndex(nodeIndex); + node->setVoxelSystem(this); + } + // populate the array with points for the 8 vertices and RGB color for each added vertex + updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); + } + return 1; // updated! } else { // If we shouldn't render, and we're in reuseIndex mode, then free our index, this only operates // on nodes with known index values, so it's safe to call for any node. @@ -1204,17 +1204,17 @@ void VoxelSystem::updateVBOs() { }; // would like to include _callsToTreesToArrays PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); - if (! _usePrimitiveRenderer) { - if (_voxelsDirty) { - if (_readRenderFullVBO) { - updateFullVBOs(); - } else { - updatePartialVBOs(); - } - _voxelsDirty = false; - _readRenderFullVBO = false; - } - } + if (! _usePrimitiveRenderer) { + if (_voxelsDirty) { + if (_readRenderFullVBO) { + updateFullVBOs(); + } else { + updatePartialVBOs(); + } + _voxelsDirty = false; + _readRenderFullVBO = false; + } + } _callsToTreesToArrays = 0; // clear it } @@ -1341,7 +1341,7 @@ void VoxelSystem::render(bool texture) { glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); } } else - if (!_usePrimitiveRenderer) { + if (!_usePrimitiveRenderer) { PerformanceWarning warn(showWarnings, "render().. TRIANGLES..."); { @@ -1415,12 +1415,12 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } } - else { - applyScaleAndBindProgram(texture); - _renderer->render(); - removeScaleAndReleaseProgram(texture); + else { + applyScaleAndBindProgram(texture); + _renderer->render(); + removeScaleAndReleaseProgram(texture); - } + } } void VoxelSystem::applyScaleAndBindProgram(bool texture) { @@ -1485,7 +1485,7 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; voxel->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - voxel->setPrimitiveIndex(0); + voxel->setPrimitiveIndex(0); return true; } @@ -1503,72 +1503,72 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; - // Nothing to do at the leaf level - if (voxel->isLeaf()) { - return false; - } + // Nothing to do at the leaf level + if (voxel->isLeaf()) { + return false; + } - // Bit mask of occluded shared faces indexed by child - unsigned char occludedSharedFace[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + // Bit mask of occluded shared faces indexed by child + unsigned char occludedSharedFace[NUMBER_OF_CHILDREN] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - // Traverse all pair combinations of children - for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { + // Traverse all pair combinations of children + for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { - VoxelTreeElement* childA = voxel->getChildAtIndex(i); - if (childA) { + VoxelTreeElement* childA = voxel->getChildAtIndex(i); + if (childA) { - // Get the child A's occluding faces, for a leaf that will be - // all six voxel faces, and for a non leaf, that will be - // all faces which are completely covered by four child octants. - unsigned char exteriorOcclusionsA = childA->getExteriorOcclusions(); + // Get the child A's occluding faces, for a leaf that will be + // all six voxel faces, and for a non leaf, that will be + // all faces which are completely covered by four child octants. + unsigned char exteriorOcclusionsA = childA->getExteriorOcclusions(); - if (exteriorOcclusionsA == OctreeElement::HalfSpace::None) { - // There is nothing to be done with this child, next... - continue; - } + if (exteriorOcclusionsA == OctreeElement::HalfSpace::None) { + // There is nothing to be done with this child, next... + continue; + } - for (int j = i; --j >= 0; ) { + for (int j = i; --j >= 0; ) { - VoxelTreeElement* childB = voxel->getChildAtIndex(j); - if (childB) { + VoxelTreeElement* childB = voxel->getChildAtIndex(j); + if (childB) { - // Get child B's occluding faces - unsigned char exteriorOcclusionsB = childB->getExteriorOcclusions(); + // Get child B's occluding faces + unsigned char exteriorOcclusionsB = childB->getExteriorOcclusions(); - if (exteriorOcclusionsB == OctreeElement::HalfSpace::None) { - // There is nothing to be done with this child, next... - continue; - } + if (exteriorOcclusionsB == OctreeElement::HalfSpace::None) { + // There is nothing to be done with this child, next... + continue; + } - // Determine the shared halfspace partition between siblings A and B, - // i.e., near/far, left/right, or top/bottom - unsigned char partition = _sOctantIndexToSharedBitMask[i][j] & - exteriorOcclusionsA & exteriorOcclusionsB; + // Determine the shared halfspace partition between siblings A and B, + // i.e., near/far, left/right, or top/bottom + unsigned char partition = _sOctantIndexToSharedBitMask[i][j] & + exteriorOcclusionsA & exteriorOcclusionsB; - // Determine which face of each sibling is occluded. - // Note the intentionally crossed indicies. It is necessary because - // the _sOctantIndexToBitMask is a partition occupancy mask. For - // example, if the near-left-top (NLT) and near-left-bottom (NLB) child voxels - // exist, the shared partition is top-bottom (TB), and thus the occluded - // shared face of the NLT voxel is its bottom face. - occludedSharedFace[i] |= (partition & _sOctantIndexToBitMask[j]); - occludedSharedFace[j] |= (partition & _sOctantIndexToBitMask[i]); - } - } - // Combine this voxel's interior excluded shared face only to those children which are coincident - // with the excluded face. - occludedSharedFace[i] |= (voxel->getInteriorOcclusions() & _sOctantIndexToBitMask[i]); + // Determine which face of each sibling is occluded. + // Note the intentionally crossed indicies. It is necessary because + // the _sOctantIndexToBitMask is a partition occupancy mask. For + // example, if the near-left-top (NLT) and near-left-bottom (NLB) child voxels + // exist, the shared partition is top-bottom (TB), and thus the occluded + // shared face of the NLT voxel is its bottom face. + occludedSharedFace[i] |= (partition & _sOctantIndexToBitMask[j]); + occludedSharedFace[j] |= (partition & _sOctantIndexToBitMask[i]); + } + } + // Combine this voxel's interior excluded shared face only to those children which are coincident + // with the excluded face. + occludedSharedFace[i] |= (voxel->getInteriorOcclusions() & _sOctantIndexToBitMask[i]); - // Inform the child - childA->setInteriorOcclusions(occludedSharedFace[i]); - if (occludedSharedFace[i] != OctreeElement::HalfSpace::None) { - //const glm::vec3& v = voxel->getCorner(); - //float s = voxel->getScale(); + // Inform the child + childA->setInteriorOcclusions(occludedSharedFace[i]); + if (occludedSharedFace[i] != OctreeElement::HalfSpace::None) { + //const glm::vec3& v = voxel->getCorner(); + //float s = voxel->getScale(); - //qDebug("Child %d of voxel at %f %f %f size: %f has %02x occlusions", i, v.x, v.y, v.z, s, occludedSharedFace[i]); - } - } - } + //qDebug("Child %d of voxel at %f %f %f size: %f has %02x occlusions", i, v.x, v.y, v.z, s, occludedSharedFace[i]); + } + } + } return true; } @@ -1576,71 +1576,71 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; - // Nothing to do at the leaf level - if (voxel->isLeaf()) { - return false; - } + // Nothing to do at the leaf level + if (voxel->isLeaf()) { + return false; + } - // Count of exterior occluding faces of this voxel element indexed - // by half space partition - unsigned int exteriorOcclusionsCt[6] = { 0, 0, 0, 0, 0, 0 }; + // Count of exterior occluding faces of this voxel element indexed + // by half space partition + unsigned int exteriorOcclusionsCt[6] = { 0, 0, 0, 0, 0, 0 }; - // Traverse all children - for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { + // Traverse all children + for (int i = NUMBER_OF_CHILDREN; --i >= 0; ) { - VoxelTreeElement* child = voxel->getChildAtIndex(i); - if (child) { - // Get the child's occluding faces, for a leaf, that will be - // all six voxel faces, and for a non leaf, that will be - // all faces which are completely covered by four child octants. - unsigned char exteriorOcclusionsOfChild = child->getExteriorOcclusions(); - exteriorOcclusionsOfChild &= _sOctantIndexToBitMask[i]; + VoxelTreeElement* child = voxel->getChildAtIndex(i); + if (child) { + // Get the child's occluding faces, for a leaf, that will be + // all six voxel faces, and for a non leaf, that will be + // all faces which are completely covered by four child octants. + unsigned char exteriorOcclusionsOfChild = child->getExteriorOcclusions(); + exteriorOcclusionsOfChild &= _sOctantIndexToBitMask[i]; - for (int j = 6; --j >= 0; ) { + for (int j = 6; --j >= 0; ) { - // Determine if the halfspace partition indexed by 1 << j is - // present in the exterior occlusions of the child. - unsigned char partition = exteriorOcclusionsOfChild & (1 << j); + // Determine if the halfspace partition indexed by 1 << j is + // present in the exterior occlusions of the child. + unsigned char partition = exteriorOcclusionsOfChild & (1 << j); - if (partition) { - exteriorOcclusionsCt[j]++; - } - } - } - } - { - // Derive the exterior occlusions of the voxel elements from the exclusions - // of its children - unsigned char exteriorOcclusions = OctreeElement::HalfSpace::None; - for (int i = 6; --i >= 0; ) { - if (exteriorOcclusionsCt[i] == 4) { + if (partition) { + exteriorOcclusionsCt[j]++; + } + } + } + } + { + // Derive the exterior occlusions of the voxel elements from the exclusions + // of its children + unsigned char exteriorOcclusions = OctreeElement::HalfSpace::None; + for (int i = 6; --i >= 0; ) { + if (exteriorOcclusionsCt[i] == _sNumOctantsPerHemiVoxel) { - // Exactly four octants qualify for full exterior occlusion - exteriorOcclusions |= (1 << i); - } - } + // Exactly four octants qualify for full exterior occlusion + exteriorOcclusions |= (1 << i); + } + } - // Inform the voxel element - voxel->setExteriorOcclusions(exteriorOcclusions); + // Inform the voxel element + voxel->setExteriorOcclusions(exteriorOcclusions); - if (exteriorOcclusions == OctreeElement::HalfSpace::All) { - //const glm::vec3& v = voxel->getCorner(); - //float s = voxel->getScale(); + if (exteriorOcclusions == OctreeElement::HalfSpace::All) { + //const glm::vec3& v = voxel->getCorner(); + //float s = voxel->getScale(); - //qDebug("Completely occupied voxel at %f %f %f size: %f", v.x, v.y, v.z, s); + //qDebug("Completely occupied voxel at %f %f %f size: %f", v.x, v.y, v.z, s); - // TODO: All of the exterior faces of this voxel element are - // occluders, which means that this element is completely - // occupied. Hence, the subtree from this node could be - // pruned and replaced by a leaf voxel, if the visible - // properties of the children are the same - } else if (exteriorOcclusions != OctreeElement::HalfSpace::None) { - //const glm::vec3& v = voxel->getCorner(); - //float s = voxel->getScale(); + // TODO: All of the exterior faces of this voxel element are + // occluders, which means that this element is completely + // occupied. Hence, the subtree from this node could be + // pruned and replaced by a leaf voxel, if the visible + // properties of the children are the same + } else if (exteriorOcclusions != OctreeElement::HalfSpace::None) { + //const glm::vec3& v = voxel->getCorner(); + //float s = voxel->getScale(); - //qDebug("Partially occupied voxel at %f %f %f size: %f with %02x", v.x, v.y, v.z, s, exteriorOcclusions); - } - } + //qDebug("Partially occupied voxel at %f %f %f size: %f with %02x", v.x, v.y, v.z, s, exteriorOcclusions); + } + } return true; } @@ -1648,55 +1648,55 @@ bool VoxelSystem::clearOcclusionsOperation(OctreeElement* element, void* extraDa _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; - bool rc; - if (voxel->isLeaf()) { + bool rc; + if (voxel->isLeaf()) { - // By definition the the exterior faces of a leaf voxel are - // always occluders. - voxel->setExteriorOcclusions(OctreeElement::HalfSpace::All); + // By definition the the exterior faces of a leaf voxel are + // always occluders. + voxel->setExteriorOcclusions(OctreeElement::HalfSpace::All); - // And the sibling occluders - voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); - rc = false; - } else { - voxel->setExteriorOcclusions(OctreeElement::HalfSpace::None); - voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); - rc = true; - } + // And the sibling occluders + voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); + rc = false; + } else { + voxel->setExteriorOcclusions(OctreeElement::HalfSpace::None); + voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); + rc = true; + } - return rc; + return rc; } void VoxelSystem::cullSharedFaces() { _nodeCount = 0; if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { - _useVoxelShader = false; - _usePrimitiveRenderer = true; + _useVoxelShader = false; + _usePrimitiveRenderer = true; _renderer->release(); - clearAllNodesBufferIndex(); - lockTree(); - _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); - _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); - unlockTree(); + clearAllNodesBufferIndex(); + lockTree(); + _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); + _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); + unlockTree(); - _nodeCount = 0; - lockTree(); - _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); - unlockTree(); + _nodeCount = 0; + lockTree(); + _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); + unlockTree(); qDebug("culling shared faces in %d nodes", _nodeCount); } else { - _usePrimitiveRenderer = false; + _usePrimitiveRenderer = false; _renderer->release(); - clearAllNodesBufferIndex(); - lockTree(); - _tree->recurseTreeWithOperation(clearOcclusionsOperation); - unlockTree(); + clearAllNodesBufferIndex(); + lockTree(); + _tree->recurseTreeWithOperation(clearOcclusionsOperation); + unlockTree(); qDebug("unculling shared faces in %d nodes", _nodeCount); } - _writeRenderFullVBO = true; + _writeRenderFullVBO = true; _tree->setDirtyBit(); setupNewVoxelsForDrawing(); @@ -1705,9 +1705,9 @@ void VoxelSystem::cullSharedFaces() { void VoxelSystem::showCulledSharedFaces() { if (Menu::getInstance()->isOptionChecked(MenuOption::ShowCulledSharedFaces)) { - _showCulledSharedFaces = true; + _showCulledSharedFaces = true; } else { - _showCulledSharedFaces = false; + _showCulledSharedFaces = false; } if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { cullSharedFaces(); @@ -2337,12 +2337,12 @@ bool VoxelSystem::showAllSubTreeOperation(OctreeElement* element, void* extraDat // These are both needed to force redraw... voxel->setDirtyBit(); voxel->markWithChangedTime(); - // and this? - { + // and this? + { VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->updateNodeInArrays(voxel, true, true); thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); - } + } args->nodesShown++; } @@ -2522,8 +2522,8 @@ public: nodesInVBOOverExpectedMax(0), duplicateVBOIndex(0), leafNodes(0), - culledLeafNodes(0), - nodesInPrimitiveRenderer(0) + culledLeafNodes(0), + nodesInPrimitiveRenderer(0) { hasIndexFound = new bool[maxVoxels]; memset(hasIndexFound, false, maxVoxels * sizeof(bool)); @@ -2542,8 +2542,8 @@ public: unsigned long nodesInVBOOverExpectedMax; unsigned long duplicateVBOIndex; unsigned long leafNodes; - unsigned long culledLeafNodes; ///< Number of completely culled nodes because of face sharing - unsigned long nodesInPrimitiveRenderer; + unsigned long culledLeafNodes; ///< Number of completely culled nodes because of face sharing + unsigned long nodesInPrimitiveRenderer; unsigned long expectedMax; @@ -2558,9 +2558,9 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v if (voxel->isLeaf()) { args->leafNodes++; - if (voxel->getInteriorOcclusions() == OctreeElement::HalfSpace::All) { - args->culledLeafNodes++; - } + if (voxel->getInteriorOcclusions() == OctreeElement::HalfSpace::All) { + args->culledLeafNodes++; + } } if (voxel->isColored()) { @@ -2575,16 +2575,16 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v args->dirtyNodes++; } - unsigned long nodeIndex = 0; - if (voxel->isKnownBufferIndex()) { - args->nodesInVBO++; - nodeIndex = voxel->getBufferIndex(); - } + unsigned long nodeIndex = 0; + if (voxel->isKnownBufferIndex()) { + args->nodesInVBO++; + nodeIndex = voxel->getBufferIndex(); + } - if (voxel->getPrimitiveIndex()) { - args->nodesInPrimitiveRenderer++; - nodeIndex = voxel->getPrimitiveIndex(); - } + if (voxel->getPrimitiveIndex()) { + args->nodesInPrimitiveRenderer++; + nodeIndex = voxel->getPrimitiveIndex(); + } if (voxel->isKnownBufferIndex() || (voxel->getPrimitiveIndex() != 0)) { @@ -2593,7 +2593,7 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s, culledFaces=0x%02x \n", voxel->getCorner().x, voxel->getCorner().y, voxel->getCorner().z, voxel->getScale(), nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender()), - voxel->getInteriorOcclusions()); + voxel->getInteriorOcclusions()); } if (args->hasIndexFound[nodeIndex]) { @@ -2622,14 +2622,14 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { glBufferIndex minDirty = GLBUFFER_INDEX_UNKNOWN; glBufferIndex maxDirty = 0; - if (!_usePrimitiveRenderer) { - for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { - if (_writeVoxelDirtyArray[i]) { - minDirty = std::min(minDirty,i); - maxDirty = std::max(maxDirty,i); - } - } - } + if (!_usePrimitiveRenderer) { + for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { + if (_writeVoxelDirtyArray[i]) { + minDirty = std::min(minDirty,i); + maxDirty = std::max(maxDirty,i); + } + } + } collectStatsForTreesAndVBOsArgs args(_maxVoxels); args.expectedMax = _voxelsInWriteArrays; @@ -3103,98 +3103,98 @@ void VoxelSystem::beginLoadingLocalVoxelCache() { // value corresponds to the voxel's octal code derived in "pointToVoxel" in SharedUtil.cpp, which, BTW, does *not* // correspond to the "ChildIndex" enum value in OctreeElement.h unsigned char VoxelSystem::_sOctantIndexToBitMask[8] = { - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Far, - OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Far, - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Far, - OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Near, - OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Far, + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Far, + OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Left | OctreeElement::HalfSpace::Far, + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Far, + OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Near, + OctreeElement::HalfSpace::Top | OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Far, }; // Two dimensional array map indexed by octant row and column. The mask value // indicates the two faces shared by the octants unsigned char VoxelSystem::_sOctantIndexToSharedBitMask[8][8] = { - { // Index 0: Bottom-Left-Near - 0, // Bottom-Left-Near - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Left-Far - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Left-Near - 0, // Top-Left-Far - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Right-Near - 0, // Bottom-Right-Far - 0, // Top-Right-Near - 0, // Top-Right-Far - }, - { // Index 1: Bottom-Left-Far - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Left-Near - 0, // Bottom-Left-Far - 0, // Top-Left-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Left-Far - 0, // Bottom-Right-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Right-Far - 0, // Top-Right-Near - 0, // Top-Right-Far - }, - { // Index 2: Top-Left-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Left-Near - 0, // Bottom-Left-Far - 0, // Top-Left-Near - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Left-Far - 0, // Bottom-Right-Near - 0, // Bottom-Right-Far - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Right-Near - 0, // Top-Right-Far - }, - { // Index 3: Top-Left-Far - 0, // Bottom-Left-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Left-Far - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Left-Near - 0, // Top-Left-Far - 0, // Bottom-Right-Near - 0, // Bottom-Right-Far - 0, // Top-Right-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Right-Far - }, - { // Index 4: Bottom-Right-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Left-Near - 0, // Bottom-Left-Far - 0, // Top-Left-Near - 0, // Top-Left-Far - 0, // Bottom-Right-Near - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Right-Far - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Right-Near - 0, // Top-Right-Far - }, - { // Index 5: Bottom-Right-Far - 0, // Bottom-Left-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Left-Far - 0, // Top-Left-Near - 0, // Top-Left-Far - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Right-Near - 0, // Bottom-Right-Far - 0, // Top-Right-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Right-Far - }, - { // Index 6: Top-Right-Near - 0, // Bottom-Left-Near - 0, // Bottom-Left-Far - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Left-Near - 0, // Top-Left-Far - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Right-Near - 0, // Bottom-Right-Far - 0, // Top-Right-Near - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Right-Far - }, - { // Index 7: Top-Right-Far - 0, // Bottom-Left-Near - 0, // Bottom-Left-Far - 0, // Top-Left-Near - OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Left-Far - 0, // Bottom-Right-Near - OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Right-Far - OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Right-Near - 0, // Top-Right-Far - }, + { // Index 0: Bottom-Left-Near + 0, // Bottom-Left-Near + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Left-Far + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Left-Near + 0, // Top-Left-Far + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Right-Near + 0, // Bottom-Right-Far + 0, // Top-Right-Near + 0, // Top-Right-Far + }, + { // Index 1: Bottom-Left-Far + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Left-Near + 0, // Bottom-Left-Far + 0, // Top-Left-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Left-Far + 0, // Bottom-Right-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Right-Far + 0, // Top-Right-Near + 0, // Top-Right-Far + }, + { // Index 2: Top-Left-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Left-Near + 0, // Bottom-Left-Far + 0, // Top-Left-Near + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Left-Far + 0, // Bottom-Right-Near + 0, // Bottom-Right-Far + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Right-Near + 0, // Top-Right-Far + }, + { // Index 3: Top-Left-Far + 0, // Bottom-Left-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Left-Far + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Left-Near + 0, // Top-Left-Far + 0, // Bottom-Right-Near + 0, // Bottom-Right-Far + 0, // Top-Right-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Right-Far + }, + { // Index 4: Bottom-Right-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Left-Near + 0, // Bottom-Left-Far + 0, // Top-Left-Near + 0, // Top-Left-Far + 0, // Bottom-Right-Near + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Right-Far + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Right-Near + 0, // Top-Right-Far + }, + { // Index 5: Bottom-Right-Far + 0, // Bottom-Left-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Bottom-Left-Far + 0, // Top-Left-Near + 0, // Top-Left-Far + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Bottom-Right-Near + 0, // Bottom-Right-Far + 0, // Top-Right-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Top-Right-Far + }, + { // Index 6: Top-Right-Near + 0, // Bottom-Left-Near + 0, // Bottom-Left-Far + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Left-Near + 0, // Top-Left-Far + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Right-Near + 0, // Bottom-Right-Far + 0, // Top-Right-Near + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Right-Far + }, + { // Index 7: Top-Right-Far + 0, // Bottom-Left-Near + 0, // Bottom-Left-Far + 0, // Top-Left-Near + OctreeElement::HalfSpace::Right | OctreeElement::HalfSpace::Left, // Top-Left-Far + 0, // Bottom-Right-Near + OctreeElement::HalfSpace::Bottom | OctreeElement::HalfSpace::Top, // Bottom-Right-Far + OctreeElement::HalfSpace::Near | OctreeElement::HalfSpace::Far, // Top-Right-Near + 0, // Top-Right-Far + }, }; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index e9f3a0ca8e..bd0dbdb71f 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -201,7 +201,7 @@ private: static bool inspectForExteriorOcclusionsOperation(OctreeElement* element, void* extraData); static bool inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData); static bool clearOcclusionsOperation(OctreeElement* element, void* extraData); - static bool hideOutOfViewOperation(OctreeElement* element, void* extraData); + static bool hideOutOfViewOperation(OctreeElement* element, void* extraData); static bool hideAllSubTreeOperation(OctreeElement* element, void* extraData); static bool showAllSubTreeOperation(OctreeElement* element, void* extraData); static bool showAllLocalVoxelsOperation(OctreeElement* element, void* extraData); @@ -317,11 +317,12 @@ private: void unlockTree(); bool _showCulledSharedFaces; ///< Flag visibility of culled faces - bool _usePrimitiveRenderer; ///< Flag primitive renderer for use - PrimitiveRenderer* _renderer; ///< Voxel renderer + bool _usePrimitiveRenderer; ///< Flag primitive renderer for use + PrimitiveRenderer* _renderer; ///< Voxel renderer - static unsigned char _sOctantIndexToBitMask[8]; ///< Map octant index to partition mask - static unsigned char _sOctantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask + static const int _sNumOctantsPerHemiVoxel = 4; + static unsigned char _sOctantIndexToBitMask[8]; ///< Map octant index to partition mask + static unsigned char _sOctantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask }; From 00e0ea9b0cc76fc5d02cb30c4a505f05e4960e12 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Sat, 8 Feb 2014 19:49:27 -0500 Subject: [PATCH 10/31] Use vector of primitives instead of associative map --- interface/src/PrimitiveRenderer.cpp | 101 ++++++++++++++-------------- interface/src/PrimitiveRenderer.h | 25 ++++++- 2 files changed, 75 insertions(+), 51 deletions(-) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index 2f1ab1fd05..6994c09f80 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -360,7 +360,7 @@ void PrimitiveRenderer::initializeGL() { glGenBuffers(1, &_vertexBufferId); // Set up the element array buffer containing the index ids - _maxTriElementCount = _maxCount * 3 * 2; + _maxTriElementCount = _maxCount * _sIndicesPerTri * 2; int size = _maxTriElementCount * sizeof(GLint); _gpuMemoryUsage += size; @@ -379,25 +379,27 @@ void PrimitiveRenderer::initializeGL() { glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); - // Initialize the first vertex element in the buffer to all zeros, the - // degenerate case + // Reserve the the first element for the degenerate case _vertexElementCount = 1; _triElementCount = 1; - VertexElement v; - memset(&v, 0, sizeof(v)); - - transferVertexElement(0, &v); + // Initialize the first tri element in the buffer to all zeros, the + // degenerate case deconstructTriElement(0); + // Initialize the first vertex element in the buffer to all zeros, the + // degenerate case + deconstructVertexElement(0); + GLint err = glGetError(); } void PrimitiveRenderer::initializeBookkeeping() { // Start primitive count at one, because zero is reserved for the degenerate triangle + _primitives.resize(_maxCount + 1); _primitiveCount = 1; - _cpuMemoryUsage = sizeof(PrimitiveRenderer); + _cpuMemoryUsage = sizeof(PrimitiveRenderer) + _primitives.size() * sizeof(Primitive *); } void PrimitiveRenderer::terminate() { @@ -415,6 +417,14 @@ void PrimitiveRenderer::terminateGL() { void PrimitiveRenderer::terminateBookkeeping() { + for (int i = _primitiveCount + 1; --i > 0; ) { + Primitive* primitive = _primitives[i]; + if (primitive) { + _cpuMemoryUsage -= primitive->getMemoryUsage(); + _primitives[i] = 0; + delete primitive; + } + } // Drain all of the queues, stop updating the counters while (_availableVertexElementIndex.remove() != 0) ; @@ -425,22 +435,10 @@ void PrimitiveRenderer::terminateBookkeeping() { while (_deconstructTriElementIndex.remove() != 0) ; - _vertexElementCount = 0; - _triElementCount = 0; + _vertexElementCount = 1; + _triElementCount = 1; + _primitiveCount = 1; - QMap::iterator it = _indexToPrimitiveMap.begin(); - QMap::iterator end = _indexToPrimitiveMap.end(); - - for ( ; it != end; ++it) { - Primitive* primitive = it.value(); - if (primitive) { - _cpuMemoryUsage -= primitive->getMemoryUsage(); - delete primitive; - } - } - - _cpuMemoryUsage -= _indexToPrimitiveMap.size() * sizeof(Primitive*); - _indexToPrimitiveMap.clear(); } void PrimitiveRenderer::constructElements( @@ -460,6 +458,8 @@ void PrimitiveRenderer::constructElements( vertexElementIndexList.push_back(index); VertexElement* vertex = *it; transferVertexElement(index, vertex); + } else { + break; } } } @@ -486,6 +486,8 @@ void PrimitiveRenderer::constructElements( tri->id = index; transferTriElement(index, tri->indices); + } else { + break; } } } else { @@ -510,6 +512,7 @@ void PrimitiveRenderer::deconstructElements( _deconstructTriElementIndex.add(tri->id); } } + // Return the vertex element index to the available queue, it is not necessary // to zero the data { @@ -525,7 +528,6 @@ void PrimitiveRenderer::deconstructElements( } } - // destroy primitive delete primitive; } @@ -533,11 +535,13 @@ int PrimitiveRenderer::getAvailablePrimitiveIndex() { // Check the available primitive index queue first for an available index. int index = _availablePrimitiveIndex.remove(); - // Remember that the primitive index 0 is used not used. + // Remember that the primitive index 0 is not used. if (index == 0) { // There are no primitive indices available from the queue, // make one up - index = _primitiveCount++; + if (_primitiveCount < _maxCount) { + index = _primitiveCount++; + } } return index; } @@ -581,12 +585,24 @@ void PrimitiveRenderer::deconstructTriElement( int idx ) { - // Set the element to the degenerate case. - int degenerate[3] = { 0, 0, 0 }; + // Set the tri element to the degenerate case. + static int degenerate[3] = { 0, 0, 0 }; transferTriElement(idx, degenerate); } +void PrimitiveRenderer::deconstructVertexElement( + int idx + ) { + + // Set the vertex element to the degenerate case. + VertexElement degenerate; + memset(°enerate, 0, sizeof(degenerate)); + + transferVertexElement(idx, °enerate); + +} + void PrimitiveRenderer::transferVertexElement( int idx, VertexElement* vertex @@ -603,7 +619,7 @@ void PrimitiveRenderer::transferTriElement( ) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, idx * sizeof(GLint) * 3, sizeof(GLint) * 3, tri); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, idx * _sBytesPerTriElement, _sBytesPerTriElement, tri); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } @@ -617,10 +633,9 @@ int PrimitiveRenderer::vAdd( try { // Take ownership of primitive, including responsibility // for destruction - _indexToPrimitiveMap[index] = primitive; + _primitives[index] = primitive; _constructPrimitiveIndex.add(index); _cpuMemoryUsage += primitive->getMemoryUsage(); - _cpuMemoryUsage += sizeof(Primitive*); } catch(...) { // STL failed, recycle the index _availablePrimitiveIndex.add(index); @@ -638,8 +653,9 @@ void PrimitiveRenderer::vRemove( QMutexLocker lock(&_guard); // Locate and remove the primitive by id in the associative map - Primitive* primitive = _indexToPrimitiveMap.take(index); + Primitive* primitive = _primitives[index]; if (primitive) { + _primitives[index] = 0; _cpuMemoryUsage -= primitive->getMemoryUsage(); deconstructElements(primitive); _availablePrimitiveIndex.add(index); @@ -653,19 +669,6 @@ void PrimitiveRenderer::vRelease() { QMutexLocker lock(&_guard); terminateBookkeeping(); -#if 0 - QMap::iterator it = _indexToPrimitiveMap.begin(); - QMap::iterator end = _indexToPrimitiveMap.end(); - - for ( ; it != end; ++it) { - Primitive* primitive = it->second; - if (primitive) { - it->second = 0; - deconstructElements(primitive); - _availablePrimitiveIndex.add(it->first); - } - } -#endif } void PrimitiveRenderer::vRender() { @@ -681,7 +684,7 @@ void PrimitiveRenderer::vRender() { } while ((id = _constructPrimitiveIndex.remove()) != 0) { - Primitive* primitive = _indexToPrimitiveMap[id]; + Primitive* primitive = _primitives[id]; if (primitive) { constructElements(primitive); @@ -692,10 +695,10 @@ void PrimitiveRenderer::vRender() { } } - // The application uses clockwise winding for the definition of front face, but I - // arbitrarily chose counter-clockwise (that is the gl default) to construct the triangulation + // The application uses clockwise winding for the definition of front face, this renderer + // aalso uses clockwise (that is the gl default) to construct the triangulation // so... - //glFrontFace(GL_CCW); + //glFrontFace(GL_CW); glEnable(GL_CULL_FACE); glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId); diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/PrimitiveRenderer.h index 0568d3bb0a..8c6814f244 100644 --- a/interface/src/PrimitiveRenderer.h +++ b/interface/src/PrimitiveRenderer.h @@ -48,8 +48,16 @@ typedef } TriElement; +/// Vertex element list container. +/// typedef QVector VertexElementList; + +/// Vertex element index list container. +/// typedef QVector VertexElementIndexList; + +/// Triangle element list container +/// typedef QVector TriElementList; /// @@ -120,10 +128,14 @@ private: virtual TriElementList& vTriElements() = 0; /// Release vertex elements. + /// Service implementer to provide private override for this method + /// in derived class /// virtual void vReleaseVertexElements() = 0; /// Get memory usage. + /// Service implementer to provide private override for this method + /// in derived class /// virtual int vGetMemoryUsage() = 0; @@ -132,7 +144,7 @@ private: /// /// @class Cube -/// Class for accessing the vertex and tri elements of a cube +/// Class for accessing the vertex and triangle elements of a cube /// class Cube: public Primitive { public: @@ -365,6 +377,12 @@ private: int idx ); + /// Deconstruct the vertex element from the GL buffer. + /// + void deconstructVertexElement( + int idx + ); + /// Transfer the vertex element to the GL buffer. /// void transferVertexElement( @@ -445,7 +463,7 @@ private: int _triElementCount; ///< Count of triangles int _maxTriElementCount; ///< Max count of triangles - QMap _indexToPrimitiveMap; ///< Associative map between index and primitive + QVector _primitives; ///< Vector of primitive int _primitiveCount; ///< Count of primitives Queue _availablePrimitiveIndex; ///< Queue of primitive indices available @@ -461,6 +479,9 @@ private: int _gpuMemoryUsage; int _cpuMemoryUsage; + + static const int _sIndicesPerTri = 3; + static const int _sBytesPerTriElement = sizeof(GLint) * _sIndicesPerTri; }; From 616ccd917238731980503fe136c7ea456e7d3fe1 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Mon, 10 Feb 2014 00:29:38 -0500 Subject: [PATCH 11/31] Replaced iterator with const_iterator --- interface/src/PrimitiveRenderer.cpp | 34 +++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index 6994c09f80..af9d1155d1 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -360,8 +360,8 @@ void PrimitiveRenderer::initializeGL() { glGenBuffers(1, &_vertexBufferId); // Set up the element array buffer containing the index ids - _maxTriElementCount = _maxCount * _sIndicesPerTri * 2; - int size = _maxTriElementCount * sizeof(GLint); + _maxTriElementCount = _maxCount * 2; + int size = _maxTriElementCount * _sIndicesPerTri * sizeof(GLint); _gpuMemoryUsage += size; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); @@ -371,7 +371,7 @@ void PrimitiveRenderer::initializeGL() { // Set up the array buffer in the form of array of structures // I chose AOS because it maximizes the amount of data tranferred // by a single glBufferSubData call. - _maxVertexElementCount = _maxCount * 4; + _maxVertexElementCount = _maxCount * 8; size = _maxVertexElementCount * sizeof(VertexElement); _gpuMemoryUsage += size; @@ -417,6 +417,7 @@ void PrimitiveRenderer::terminateGL() { void PrimitiveRenderer::terminateBookkeeping() { + // Delete all of the primitives for (int i = _primitiveCount + 1; --i > 0; ) { Primitive* primitive = _primitives[i]; if (primitive) { @@ -425,7 +426,8 @@ void PrimitiveRenderer::terminateBookkeeping() { delete primitive; } } - // Drain all of the queues, stop updating the counters + + // Drain the queues while (_availableVertexElementIndex.remove() != 0) ; @@ -435,6 +437,7 @@ void PrimitiveRenderer::terminateBookkeeping() { while (_deconstructTriElementIndex.remove() != 0) ; + // Reset the counters _vertexElementCount = 1; _triElementCount = 1; _primitiveCount = 1; @@ -455,7 +458,10 @@ void PrimitiveRenderer::constructElements( for ( ; it != end; ++it ) { int index = getAvailableVertexElementIndex(); if (index != 0) { + // Store the vertex element index in the primitive's + // vertex element index list vertexElementIndexList.push_back(index); + VertexElement* vertex = *it; transferVertexElement(index, vertex); } else { @@ -502,11 +508,11 @@ void PrimitiveRenderer::deconstructElements( // Schedule the tri elements of the face for deconstruction { TriElementList& tris = primitive->triElements(); - TriElementList::iterator it = tris.begin(); - TriElementList::iterator end = tris.end(); + TriElementList::const_iterator it = tris.begin(); + TriElementList::const_iterator end = tris.end(); for ( ; it != end; ++it) { - TriElement* tri = *it; + TriElement const* tri = *it; // Put the tri element index into decon queue _deconstructTriElementIndex.add(tri->id); @@ -517,8 +523,8 @@ void PrimitiveRenderer::deconstructElements( // to zero the data { VertexElementIndexList& vertexIndexList = primitive->vertexElementIndices(); - VertexElementIndexList::iterator it = vertexIndexList.begin(); - VertexElementIndexList::iterator end = vertexIndexList.end(); + VertexElementIndexList::const_iterator it = vertexIndexList.begin(); + VertexElementIndexList::const_iterator end = vertexIndexList.end(); for ( ; it != end; ++it) { int index = *it; @@ -563,15 +569,15 @@ int PrimitiveRenderer::getAvailableVertexElementIndex() { int PrimitiveRenderer::getAvailableTriElementIndex() { - // Check the deconstruct tri element queue first for an available index. + // Check the tri elements scheduled for deconstruction queue first to + // intercept and reuse an index without it having to be destroyed int index = _deconstructTriElementIndex.remove(); - // Remember that the tri element 0 is used for degenerate triangles. if (index == 0) { - // There are no tri elements in the deconstruct tri element queue that are reusable. - // Check the available tri element queue. + // Nothing available in the deconstruction queue, now + // check the available tri element queue for an available index. index = _availableTriElementIndex.remove(); if (index == 0) { - // There are no reusable tri elements available from any queue, + // There are no reusable tri elements available from the queue, // grab one from the end of the list if (_triElementCount < _maxTriElementCount) { index = _triElementCount++; From a3ce69bcbb825c73ad63edf0f373dbb89b745cfe Mon Sep 17 00:00:00 2001 From: matsukaze Date: Mon, 10 Feb 2014 01:44:27 -0500 Subject: [PATCH 12/31] Removed duplicate pathway to updateNodeInArrays from showAllSubTreeOperation --- interface/src/VoxelSystem.cpp | 70 ++++++++++++++++++++++------------- interface/src/VoxelSystem.h | 8 ++-- 2 files changed, 49 insertions(+), 29 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 82f72bfb4d..576286ab33 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -60,6 +60,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _treeScale(treeScale), _maxVoxels(maxVoxels), _initialized(false), + _inInspectForOcclusions(false), _showCulledSharedFaces(false), _usePrimitiveRenderer(false), _renderer(0) { @@ -1028,7 +1029,6 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo } else { node->setVoxelSystem(this); } - inspectForInteriorOcclusionsOperation(node, 0); unsigned char occlusions; if (_showCulledSharedFaces) { occlusions = ~node->getInteriorOcclusions(); @@ -1675,15 +1675,7 @@ void VoxelSystem::cullSharedFaces() { _usePrimitiveRenderer = true; _renderer->release(); clearAllNodesBufferIndex(); - lockTree(); - _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); - _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); - unlockTree(); - - _nodeCount = 0; - lockTree(); - _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); - unlockTree(); + inspectForOcclusions(); qDebug("culling shared faces in %d nodes", _nodeCount); } else { _usePrimitiveRenderer = false; @@ -1710,10 +1702,32 @@ void VoxelSystem::showCulledSharedFaces() { _showCulledSharedFaces = false; } if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { - cullSharedFaces(); + _writeRenderFullVBO = true; + _tree->setDirtyBit(); + setupNewVoxelsForDrawing(); } } +void VoxelSystem::inspectForOcclusions() { + + // don't re-enter... + if (_inInspectForOcclusions) { + return; + } + + _inInspectForOcclusions = true; + + bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showDebugDetails, "inspectForOcclusions()"); + + lockTree(); + _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); + _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); + unlockTree(); + + _inInspectForOcclusions = false; +} + bool VoxelSystem::forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData) { _nodeCount++; element->setDirtyBit(); @@ -2338,11 +2352,12 @@ bool VoxelSystem::showAllSubTreeOperation(OctreeElement* element, void* extraDat voxel->setDirtyBit(); voxel->markWithChangedTime(); // and this? - { - VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; - thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->updateNodeInArrays(voxel, true, true); - thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); - } +// no, not needed, because markWithChangedTime notifies hooks, which calls elementUpdated, which calls updateNodeInArrays +// { +// VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; +// thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->updateNodeInArrays(voxel, true, true); +// thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); +// } args->nodesShown++; } @@ -2386,7 +2401,6 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData // we need to hide it. Additionally we know that ALL of it's children are also fully OUTSIDE so we can recurse // the children and simply mark them as hidden args->tree->recurseNodeWithOperation(voxel, hideAllSubTreeOperation, args ); - return false; } break; @@ -2576,25 +2590,29 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v } unsigned long nodeIndex = 0; - if (voxel->isKnownBufferIndex()) { - args->nodesInVBO++; - nodeIndex = voxel->getBufferIndex(); - } - if (voxel->getPrimitiveIndex()) { args->nodesInPrimitiveRenderer++; nodeIndex = voxel->getPrimitiveIndex(); - } - - if (voxel->isKnownBufferIndex() || (voxel->getPrimitiveIndex() != 0)) { const bool extraDebugging = false; // enable for extra debugging if (extraDebugging) { - qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s, culledFaces=0x%02x \n", + qDebug("node In Renderer... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s, culledFaces=0x%02x \n", voxel->getCorner().x, voxel->getCorner().y, voxel->getCorner().z, voxel->getScale(), nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender()), voxel->getInteriorOcclusions()); } + } + + if (voxel->isKnownBufferIndex()) { + args->nodesInVBO++; + nodeIndex = voxel->getBufferIndex(); + + const bool extraDebugging = false; // enable for extra debugging + if (extraDebugging) { + qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s \n", + voxel->getCorner().x, voxel->getCorner().y, voxel->getCorner().z, voxel->getScale(), + nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender())); + } if (args->hasIndexFound[nodeIndex]) { args->duplicateVBOIndex++; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index bd0dbdb71f..0d93165b98 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -85,6 +85,7 @@ public: virtual void removeOutOfView(); virtual void hideOutOfView(bool forceFullFrustum = false); + void inspectForOcclusions(); bool hasViewChanged(); bool isViewChanging(); @@ -317,11 +318,12 @@ private: void unlockTree(); bool _showCulledSharedFaces; ///< Flag visibility of culled faces - bool _usePrimitiveRenderer; ///< Flag primitive renderer for use - PrimitiveRenderer* _renderer; ///< Voxel renderer + bool _inInspectForOcclusions; ///< Flag occupancy of inspectForOcclusions method + bool _usePrimitiveRenderer; ///< Flag primitive renderer for use + PrimitiveRenderer* _renderer; ///< Voxel renderer static const int _sNumOctantsPerHemiVoxel = 4; - static unsigned char _sOctantIndexToBitMask[8]; ///< Map octant index to partition mask + static unsigned char _sOctantIndexToBitMask[8]; ///< Map octant index to partition mask static unsigned char _sOctantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask }; From b1dd849a1a08a4d5eb18129cdbca1681c0773889 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Mon, 10 Feb 2014 09:03:53 -0500 Subject: [PATCH 13/31] Must drain the primitive construction queue during release --- interface/src/PrimitiveRenderer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index af9d1155d1..e0bb797fca 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -437,11 +437,15 @@ void PrimitiveRenderer::terminateBookkeeping() { while (_deconstructTriElementIndex.remove() != 0) ; + while (_constructPrimitiveIndex.remove() != 0) + ; + // Reset the counters _vertexElementCount = 1; _triElementCount = 1; _primitiveCount = 1; + _cpuMemoryUsage = sizeof(PrimitiveRenderer) + _primitives.size() * sizeof(Primitive *); } void PrimitiveRenderer::constructElements( From 5ce1b650e899bfa93744f08e2bfc54b213b0c8a4 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 11 Feb 2014 19:27:05 -0500 Subject: [PATCH 14/31] Replaced custom Queue with QStack --- interface/src/PrimitiveRenderer.cpp | 123 +++++++++++++++------------- interface/src/PrimitiveRenderer.h | 13 ++- 2 files changed, 73 insertions(+), 63 deletions(-) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index e0bb797fca..6e4dcd12dd 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -379,10 +379,6 @@ void PrimitiveRenderer::initializeGL() { glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); - // Reserve the the first element for the degenerate case - _vertexElementCount = 1; - _triElementCount = 1; - // Initialize the first tri element in the buffer to all zeros, the // degenerate case deconstructTriElement(0); @@ -398,8 +394,19 @@ void PrimitiveRenderer::initializeBookkeeping() { // Start primitive count at one, because zero is reserved for the degenerate triangle _primitives.resize(_maxCount + 1); + + // Set the counters _primitiveCount = 1; - _cpuMemoryUsage = sizeof(PrimitiveRenderer) + _primitives.size() * sizeof(Primitive *); + _vertexElementCount = 1; + _triElementCount = 1; + + // Guesstimate the memory consumption + _cpuMemoryUsage = sizeof(PrimitiveRenderer); + _cpuMemoryUsage += _availablePrimitiveIndex.capacity() * sizeof(int); + _cpuMemoryUsage += _availableVertexElementIndex.capacity() * sizeof(int); + _cpuMemoryUsage += _availableTriElementIndex.capacity() * sizeof(int); + _cpuMemoryUsage += _deconstructTriElementIndex.capacity() * sizeof(int); + _cpuMemoryUsage += _constructPrimitiveIndex.capacity() * sizeof(int); } void PrimitiveRenderer::terminate() { @@ -428,22 +435,11 @@ void PrimitiveRenderer::terminateBookkeeping() { } // Drain the queues - while (_availableVertexElementIndex.remove() != 0) - ; - - while (_availableTriElementIndex.remove() != 0) - ; - - while (_deconstructTriElementIndex.remove() != 0) - ; - - while (_constructPrimitiveIndex.remove() != 0) - ; - - // Reset the counters - _vertexElementCount = 1; - _triElementCount = 1; - _primitiveCount = 1; + _availablePrimitiveIndex.clear(); + _availableVertexElementIndex.clear(); + _availableTriElementIndex.clear(); + _deconstructTriElementIndex.clear(); + _constructPrimitiveIndex.clear(); _cpuMemoryUsage = sizeof(PrimitiveRenderer) + _primitives.size() * sizeof(Primitive *); } @@ -519,7 +515,7 @@ void PrimitiveRenderer::deconstructElements( TriElement const* tri = *it; // Put the tri element index into decon queue - _deconstructTriElementIndex.add(tri->id); + _deconstructTriElementIndex.push(tri->id); } } @@ -534,7 +530,7 @@ void PrimitiveRenderer::deconstructElements( int index = *it; // Put the vertex element index into the available queue - _availableVertexElementIndex.add(index); + _availableVertexElementIndex.push(index); } } @@ -543,50 +539,56 @@ void PrimitiveRenderer::deconstructElements( int PrimitiveRenderer::getAvailablePrimitiveIndex() { + int index; + // Check the available primitive index queue first for an available index. - int index = _availablePrimitiveIndex.remove(); - // Remember that the primitive index 0 is not used. - if (index == 0) { + if (!_availablePrimitiveIndex.isEmpty()) { + index = _availablePrimitiveIndex.pop(); + } else if (_primitiveCount < _maxCount) { // There are no primitive indices available from the queue, // make one up - if (_primitiveCount < _maxCount) { - index = _primitiveCount++; - } + index = _primitiveCount++; + } else { + index = 0; } return index; } int PrimitiveRenderer::getAvailableVertexElementIndex() { + int index; + // Check the available vertex element queue first for an available index. - int index = _availableVertexElementIndex.remove(); - // Remember that the vertex element 0 is used for degenerate triangles. - if (index == 0) { + if (!_availableVertexElementIndex.isEmpty()) { + index = _availableVertexElementIndex.pop(); + } else if (_vertexElementCount < _maxVertexElementCount) { // There are no vertex elements available from the queue, // grab one from the end of the list - if (_vertexElementCount < _maxVertexElementCount) { - index = _vertexElementCount++; - } + index = _vertexElementCount++; + } else { + index = 0; } return index; } int PrimitiveRenderer::getAvailableTriElementIndex() { + int index; + // Check the tri elements scheduled for deconstruction queue first to // intercept and reuse an index without it having to be destroyed - int index = _deconstructTriElementIndex.remove(); - if (index == 0) { + if (!_deconstructTriElementIndex.isEmpty()) { + index = _deconstructTriElementIndex.pop(); + } else if (!_availableTriElementIndex.isEmpty()) { // Nothing available in the deconstruction queue, now // check the available tri element queue for an available index. - index = _availableTriElementIndex.remove(); - if (index == 0) { - // There are no reusable tri elements available from the queue, - // grab one from the end of the list - if (_triElementCount < _maxTriElementCount) { - index = _triElementCount++; - } - } + index = _availableTriElementIndex.pop(); + } else if (_triElementCount < _maxTriElementCount) { + // There are no reusable tri elements available from the queue, + // grab one from the end of the list + index = _triElementCount++; + } else { + index = 0; } return index; } @@ -644,11 +646,11 @@ int PrimitiveRenderer::vAdd( // Take ownership of primitive, including responsibility // for destruction _primitives[index] = primitive; - _constructPrimitiveIndex.add(index); + _constructPrimitiveIndex.push(index); _cpuMemoryUsage += primitive->getMemoryUsage(); } catch(...) { - // STL failed, recycle the index - _availablePrimitiveIndex.add(index); + // Qt failed, recycle the index + _availablePrimitiveIndex.push(index); index = 0; } } @@ -662,23 +664,27 @@ void PrimitiveRenderer::vRemove( try { QMutexLocker lock(&_guard); - // Locate and remove the primitive by id in the associative map + // Locate and remove the primitive by id in the vector map Primitive* primitive = _primitives[index]; if (primitive) { _primitives[index] = 0; _cpuMemoryUsage -= primitive->getMemoryUsage(); deconstructElements(primitive); - _availablePrimitiveIndex.add(index); + + // Queue the index onto the available primitive stack. + _availablePrimitiveIndex.push(index); } } catch(...) { - // STL failed + // Qt failed } } void PrimitiveRenderer::vRelease() { QMutexLocker lock(&_guard); + terminateBookkeeping(); + initializeBookkeeping(); } void PrimitiveRenderer::vRender() { @@ -686,14 +692,19 @@ void PrimitiveRenderer::vRender() { QMutexLocker lock(&_guard); - // Now would be an appropriate time to set the element array buffer ids - // scheduled for deconstruction to the degenerate case. - while ((id = _deconstructTriElementIndex.remove()) != 0) { + // Iterate over the set of triangle element array buffer ids scheduled for + // destruction. Set the triangle element to the degenerate case. Queue the id + // onto the available tri element stack. + while (!_deconstructTriElementIndex.isEmpty()) { + id = _deconstructTriElementIndex.pop(); deconstructTriElement(id); - _availableTriElementIndex.add(id); + _availableTriElementIndex.push(id); } - while ((id = _constructPrimitiveIndex.remove()) != 0) { + // Iterate over the set of primitive ids scheduled for construction. Transfer + // primitive data to the GPU. + while (!_constructPrimitiveIndex.isEmpty()) { + id = _constructPrimitiveIndex.pop(); Primitive* primitive = _primitives[id]; if (primitive) { constructElements(primitive); diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/PrimitiveRenderer.h index 8c6814f244..fa99fe5b71 100644 --- a/interface/src/PrimitiveRenderer.h +++ b/interface/src/PrimitiveRenderer.h @@ -9,11 +9,10 @@ #ifndef __interface__PrimitiveRenderer__ #define __interface__PrimitiveRenderer__ +#include #include #include -#include "Queue.h" - /// Vertex element structure. /// Using the array of structures approach to specifying /// vertex data to GL cuts down on the calls to glBufferSubData @@ -466,11 +465,11 @@ private: QVector _primitives; ///< Vector of primitive int _primitiveCount; ///< Count of primitives - Queue _availablePrimitiveIndex; ///< Queue of primitive indices available - Queue _availableVertexElementIndex; ///< Queue of vertex element indices available - Queue _availableTriElementIndex; ///< Queue of triangle element indices available - Queue _deconstructTriElementIndex; ///< Queue of triangle element indices requiring deletion from GL - Queue _constructPrimitiveIndex; ///< Queue of primitives requiring addition to GL + QStack _availablePrimitiveIndex; ///< Queue of primitive indices available + QStack _availableVertexElementIndex; ///< Queue of vertex element indices available + QStack _availableTriElementIndex; ///< Queue of triangle element indices available + QStack _deconstructTriElementIndex; ///< Queue of triangle element indices requiring deletion from GL + QStack _constructPrimitiveIndex; ///< Queue of primitives requiring addition to GL QMutex _guard; From 095f5292cd4ef5e29ec4d6f9cc75bd8d55d9736e Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 11 Feb 2014 20:12:44 -0500 Subject: [PATCH 15/31] Deprecated custom containers --- interface/src/AutoLock.h | 84 ------------ interface/src/Mutex.h | 146 -------------------- interface/src/Queue.h | 272 -------------------------------------- interface/src/Threading.h | 78 ----------- 4 files changed, 580 deletions(-) delete mode 100644 interface/src/AutoLock.h delete mode 100644 interface/src/Mutex.h delete mode 100644 interface/src/Queue.h delete mode 100644 interface/src/Threading.h diff --git a/interface/src/AutoLock.h b/interface/src/AutoLock.h deleted file mode 100644 index 65746f85b5..0000000000 --- a/interface/src/AutoLock.h +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file AutoLock.h - * A simple locking class featuring templated mutex policy and mutex barrier - * activation/deactivation constructor/destructor. - * - * @author Norman Crafts - * @copyright 2014, All rights reserved. - */ -#ifndef __AUTOLOCK_H__ -#define __AUTOLOCK_H__ - -#include "Mutex.h" - -/** - * @class AutoLock - */ -template -< - class MutexPolicy = Mutex -> -class AutoLock -{ -public: - /** Dependency injection constructor - * AutoLock constructor with client mutex injection - */ - AutoLock( - MutexPolicy & client ///< Client mutex - ); - - /** Dependency injection constructor - * AutoLock constructor with client mutex injection - */ - AutoLock( - MutexPolicy *client ///< Client mutex - ); - - ~AutoLock(); - -private: - /** Default constructor prohibited to API user - */ - AutoLock(); - - /** Copy constructor prohibited to API user - */ - AutoLock( - AutoLock const & copy - ); - -private: - MutexPolicy &_mutex; ///< Client mutex -}; - - -template -inline -AutoLock::AutoLock( - MutexPolicy &mutex - ) : - _mutex(mutex) -{ - _mutex.lock(); -} - -template -inline -AutoLock::AutoLock( - MutexPolicy *mutex - ) : - _mutex(*mutex) -{ - _mutex.lock(); -} - -template -inline -AutoLock::~AutoLock() -{ - _mutex.unlock(); -} - - -#endif // __AUTOLOCK_H__ diff --git a/interface/src/Mutex.h b/interface/src/Mutex.h deleted file mode 100644 index e08cf4407f..0000000000 --- a/interface/src/Mutex.h +++ /dev/null @@ -1,146 +0,0 @@ -/** - * @file Mutex.h - * An operating system independent simple wrapper to mutex services. - * - * @author: Norman Crafts - * @copyright 2014, All rights reserved. - */ -#ifndef __MUTEX_H__ -#define __MUTEX_H__ - -#ifdef LINUX -#include -#include -#endif - -/** - * @class Mutex - * - * This class is an OS independent delegate pattern providing access - * to simple OS dependent mutex services. Assume the mutex service is - * non-reentrant. - */ -class Mutex -{ -public: - /** Default constructor - */ - Mutex(); - - ~Mutex(); - - /** Lock the mutex barrier - * First competing thread will capture the mutex and block all - * other threads. - */ - void lock(); - - /** Unlock the mutex barrier - * Mutex owner releases the mutex and allow competing threads to try to capture. - */ - void unlock(); - -private: - /** Copy constructor prohibited to API user - */ - Mutex( - Mutex const & copy - ); - -private: - -#ifdef _DEBUG - int _lockCt; -#endif //_DEBUG - -#ifdef WIN32 - CRITICAL_SECTION _mutex; -#endif // WIN32 - -#ifdef LINUX - pthread_mutex_t _mutex; -#endif // LINUX -}; - - -#ifdef WIN32 - -inline -Mutex::Mutex() -#ifdef _DEBUG - : - _lockCt(0) -#endif -{ - InitializeCriticalSection(&_mutex); -} - -inline -Mutex::~Mutex() -{ - DeleteCriticalSection(&_mutex); -} - -inline -void Mutex::lock() -{ - EnterCriticalSection(&_mutex); - #ifdef _DEBUG - _lockCt++; - #endif // _DEBUG -} - -inline -void Mutex::unlock() -{ - #ifdef _DEBUG - _lockCt--; - #endif // _DEBUG - LeaveCriticalSection(&_mutex); -} - -#endif // WIN32 - -#ifdef LINUX - -inline -Mutex::Mutex() -#ifdef _DEBUG - : - _lockCt(0) -#endif -{ - int err; - pthread_mutexattr_t attrib; - - err = pthread_mutexattr_init(&attrib); - err = pthread_mutex_init(&_mutex, &attrib); - err = pthread_mutexattr_destroy(&attrib); -} - -inline -Mutex::~Mutex() -{ - pthread_mutex_destroy(&_mutex); -} - -inline -void Mutex::lock() -{ - pthread_mutex_lock(&_mutex); - #ifdef _DEBUG - _lockCt++; - #endif // _DEBUG -} - -inline -void Mutex::unlock() -{ - #ifdef _DEBUG - _lockCt--; - #endif // _DEBUG - pthread_mutex_unlock(&_mutex); -} - -#endif // LINUX -#endif // __MUTEX_H__ diff --git a/interface/src/Queue.h b/interface/src/Queue.h deleted file mode 100644 index 8536b9111d..0000000000 --- a/interface/src/Queue.h +++ /dev/null @@ -1,272 +0,0 @@ -/** - * @file Queue.h - * An efficient FIFO queue featuring lock-free interaction between - * producer and consumer. - * - * @author: Norman Crafts - * @copyright 2014, All rights reserved. - */ -#ifndef __QUEUE_H__ -#define __QUEUE_H__ - -#include "AutoLock.h" -#include "Mutex.h" -#include "Threading.h" - -/** - * @class Queue - * - * A template based, efficient first-in/first-out queue featuring lock free - * access between producer and consumer. - */ -template -< - class Client, // Managed client class - template class ProducerThreadingPolicy = MultiThreaded, - template class ConsumerThreadingPolicy = MultiThreaded, - class ProducerMutexPolicy = Mutex, - class ConsumerMutexPolicy = Mutex -> -class Queue -{ -public: - /** Default constructor - */ - Queue(); - - ~Queue(); - - /** Add an object of managed client class to the tail of the queue - */ - void add( - Client item - ); - - /** Remove an object of managed client class from the head of the queue - */ - Client remove(); - - /** Peek at an object of managed client class at the head of the queue - * but do not remove it. - */ - Client peek(); - - /** Is the queue empty? - */ - bool isEmpty(); - -private: - struct __node - { - /** Default node constructor - */ - __node() : - _item(), - _next(0) - {} - - /** Item injection constructor - */ - __node( - Client item - ) : - _item(item), - _next(0) - {} - - Client _item; - struct __node *_next; - }; - - static const int s_cacheLineSize = 64; ///< Cache line size (in bytes) of standard Intel architecture - char pad0[s_cacheLineSize]; ///< Padding to eliminate cache line contention between threads - - ProducerThreadingPolicy _producerGuard; - char pad1[s_cacheLineSize - sizeof(ProducerThreadingPolicy)]; - - ConsumerThreadingPolicy _consumerGuard; - char pad2[s_cacheLineSize - sizeof(ConsumerThreadingPolicy)]; - - struct __node *_first; ///< Queue management - char pad3[s_cacheLineSize - sizeof(struct __node *)]; - - struct __node *_last; ///< Queue management - char pad4[s_cacheLineSize - sizeof(struct __node *)]; -}; - - - - - - - - -template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > -Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::Queue() -{ - _first = new __node(); - _last = _first; - memset(pad0, 0, sizeof(pad0)); - memset(pad1, 0, sizeof(pad1)); - memset(pad2, 0, sizeof(pad2)); - memset(pad3, 0, sizeof(pad3)); - memset(pad4, 0, sizeof(pad4)); -} - -template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > -Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::~Queue() -{ - AutoLock > lock(_consumerGuard); - while (_first) - { - struct __node *t = _first; - _first = t->_next; - delete t; - } -} - - -template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > -void Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::add( - Client item - ) -{ - struct __node *n = new __node(item); - AutoLock > lock(_producerGuard); - _last->_next = n; - _last = n; -} - - - -template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > -Client Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::remove() -{ - AutoLock > lock(_consumerGuard); - struct __node *next = _first->_next; - if (next) - { - struct __node *first = _first; - Client item = next->_item; - next->_item = 0; - _first = next; - delete first; - return item; - } - return 0; -} - - - -template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > -Client Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::peek() -{ - AutoLock > lock(_consumerGuard); - struct __node *next = _first->_next; - if (next) - { - Client item = next->_item; - return item; - } - return 0; -} - - - -template - < - class Client, - template class ProducerThreadingPolicy, - template class ConsumerThreadingPolicy, - class ProducerMutexPolicy, - class ConsumerMutexPolicy - > -bool Queue - < - Client, - ProducerThreadingPolicy, - ConsumerThreadingPolicy, - ProducerMutexPolicy, - ConsumerMutexPolicy - >::isEmpty() -{ - bool empty = true; - AutoLock > lock(_consumerGuard); - struct __node *next = _first->_next; - if (next) - empty = false; - - return empty; -} - -#endif // __QUEUE_H__ diff --git a/interface/src/Threading.h b/interface/src/Threading.h deleted file mode 100644 index 02870fed44..0000000000 --- a/interface/src/Threading.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file Threading.h - * A delegate pattern to encapsulate threading policy semantics. - * - * @author: Norman Crafts - * @copyright 2014, All rights reserved. - */ -#ifndef __THREADING_H__ -#define __THREADING_H__ - -/** - * @class SingleThreaded - */ -template -< - class MutexPolicy = Mutex ///< Mutex policy -> -class SingleThreaded -{ -public: - - void lock(); - - void unlock(); -}; - -/** - * @class MultiThreaded - */ -template -< - class MutexPolicy = Mutex ///< Mutex policy -> -class MultiThreaded -{ -public: - - void lock(); - - void unlock(); - -private: - MutexPolicy _mutex; -}; - - - - -template -inline -void SingleThreaded::lock() -{} - -template -inline -void SingleThreaded::unlock() -{} - - - - - -template -inline -void MultiThreaded::lock() -{ - _mutex.lock(); -} - -template -inline -void MultiThreaded::unlock() -{ - _mutex.unlock(); -} - - -#endif // __THREADING_H__ From 25f87093f2ed1d3ca6a503e2ce75bbbcad2a2af7 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Thu, 13 Feb 2014 10:03:41 -0500 Subject: [PATCH 16/31] Fixes for tyle conformance --- interface/src/PrimitiveRenderer.cpp | 72 ++++++++++++----------------- interface/src/PrimitiveRenderer.h | 18 ++++---- 2 files changed, 38 insertions(+), 52 deletions(-) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index 6e4dcd12dd..9da6d6b288 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -1,10 +1,10 @@ -/** - * @file PrimitiveRenderer.cpp - * A geometric primitive renderer. - * - * @author: Norman Crafts - * @copyright 2014, High Fidelity, Inc. All rights reserved. - */ +/// +/// @file PrimitiveRenderer.cpp +/// A geometric primitive renderer. +/// +/// @author: Norman Crafts +/// @copyright 2014, High Fidelity, Inc. All rights reserved. +/// #include @@ -20,7 +20,7 @@ Primitive::~Primitive() { // Simple dispatch between API and SPI -VertexElementList const & Primitive::vertexElements() const { +const VertexElementList& Primitive::vertexElements() const { return vVertexElements(); } @@ -52,14 +52,14 @@ Cube::Cube( unsigned char faceExclusions ) : _cpuMemoryUsage(0) { - initialize(x, y, z, s, r, g, b, faceExclusions); + init(x, y, z, s, r, g, b, faceExclusions); } Cube::~Cube() { terminate(); } -void Cube::initialize( +void Cube::init( float x, float y, float z, @@ -93,9 +93,10 @@ void Cube::initializeVertices( for (int i = 0; i < _sNumVerticesPerCube; i++) { // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. + // uncomment this line to load all faces: if (~0x00 & _sFaceIndexToHalfSpaceMask[i >> 2]) { + // uncomment this line to include shared faces: if (faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { + // uncomment this line to exclude shared faces: if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { - //if (~0x00 & _sFaceIndexToHalfSpaceMask[i >> 2]) { - //if (faceExclusions & _sFaceIndexToHalfSpaceMask[i >> 2]) { VertexElement* v = new VertexElement(); if (v) { @@ -142,10 +143,7 @@ void Cube::initializeVertices( void Cube::terminateVertices() { - VertexElementList::iterator it = _vertices.begin(); - VertexElementList::iterator end = _vertices.end(); - - for ( ; it != end; ++it) { + for (VertexElementList::iterator it = _vertices.begin(); it != _vertices.end(); ++it) { delete *it; } _cpuMemoryUsage -= _vertices.size() * (sizeof(VertexElement) + sizeof(VertexElement*)); @@ -159,10 +157,10 @@ void Cube::initializeTris( int index = 0; for (int i = 0; i < _sNumFacesPerCube; i++) { // Check whether the vertex is necessary for the faces indicated by faceExclusions bit mask. - // uncomment this line to exclude shared faces: - if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { // uncomment this line to load all faces: if (~0x00 & _sFaceIndexToHalfSpaceMask[i]) { // uncomment this line to include shared faces: if (faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { + // uncomment this line to exclude shared faces: + if (~faceExclusions & _sFaceIndexToHalfSpaceMask[i]) { int start = index; // Create the triangulated face, two tris, six indices referencing four vertices, both @@ -174,7 +172,7 @@ void Cube::initializeTris( // Store triangle ABC - TriElement *tri = new TriElement(); + TriElement* tri = new TriElement(); if (tri) { tri->indices[0] = index++; tri->indices[1] = index++; @@ -204,17 +202,14 @@ void Cube::initializeTris( void Cube::terminateTris() { - TriElementList::iterator it = _tris.begin(); - TriElementList::iterator end = _tris.end(); - - for ( ; it != end; ++it) { + for (TriElementList::iterator it = _tris.begin(); it != _tris.end(); ++it) { delete *it; } _cpuMemoryUsage -= _tris.size() * (sizeof(TriElement) + sizeof(TriElement*)); _tris.clear(); } -VertexElementList const & Cube::vVertexElements() const { +const VertexElementList& Cube::vVertexElements() const { return _vertices; } @@ -340,7 +335,7 @@ PrimitiveRenderer::PrimitiveRenderer( _cpuMemoryUsage(0) { - initialize(); + init(); } PrimitiveRenderer::~PrimitiveRenderer() { @@ -348,7 +343,7 @@ PrimitiveRenderer::~PrimitiveRenderer() { terminate(); } -void PrimitiveRenderer::initialize() { +void PrimitiveRenderer::init() { initializeGL(); initializeBookkeeping(); @@ -450,12 +445,9 @@ void PrimitiveRenderer::constructElements( // Load vertex elements VertexElementIndexList& vertexElementIndexList = primitive->vertexElementIndices(); - VertexElementList const & vertices = primitive->vertexElements(); + const VertexElementList& vertices = primitive->vertexElements(); { - VertexElementList::const_iterator it = vertices.begin(); - VertexElementList::const_iterator end = vertices.end(); - - for ( ; it != end; ++it ) { + for (VertexElementList::const_iterator it = vertices.begin(); it != vertices.end(); ++it ) { int index = getAvailableVertexElementIndex(); if (index != 0) { // Store the vertex element index in the primitive's @@ -473,10 +465,8 @@ void PrimitiveRenderer::constructElements( // Load tri elements if (vertexElementIndexList.size() == vertices.size()) { TriElementList& tris = primitive->triElements(); - TriElementList::iterator it = tris.begin(); - TriElementList::iterator end = tris.end(); - for ( ; it != end; ++it) { + for (TriElementList::iterator it = tris.begin(); it != tris.end(); ++it) { TriElement* tri = *it; int index = getAvailableTriElementIndex(); if (index != 0) { @@ -508,11 +498,9 @@ void PrimitiveRenderer::deconstructElements( // Schedule the tri elements of the face for deconstruction { TriElementList& tris = primitive->triElements(); - TriElementList::const_iterator it = tris.begin(); - TriElementList::const_iterator end = tris.end(); - for ( ; it != end; ++it) { - TriElement const* tri = *it; + for (TriElementList::const_iterator it = tris.begin(); it != tris.end(); ++it) { + const TriElement* tri = *it; // Put the tri element index into decon queue _deconstructTriElementIndex.push(tri->id); @@ -523,10 +511,8 @@ void PrimitiveRenderer::deconstructElements( // to zero the data { VertexElementIndexList& vertexIndexList = primitive->vertexElementIndices(); - VertexElementIndexList::const_iterator it = vertexIndexList.begin(); - VertexElementIndexList::const_iterator end = vertexIndexList.end(); - for ( ; it != end; ++it) { + for (VertexElementIndexList::const_iterator it = vertexIndexList.begin(); it != vertexIndexList.end(); ++it) { int index = *it; // Put the vertex element index into the available queue @@ -728,10 +714,10 @@ void PrimitiveRenderer::vRender() { glVertexPointer(3, GL_FLOAT, sizeof(VertexElement), 0); glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexElement), (GLvoid const *)12); + glNormalPointer(GL_FLOAT, sizeof(VertexElement), (const GLvoid*)12); glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexElement), (GLvoid const *)24); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexElement), (const GLvoid*)24); glBindBuffer(GL_ARRAY_BUFFER, 0); GLint err = glGetError(); diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/PrimitiveRenderer.h index fa99fe5b71..a1b867c16a 100644 --- a/interface/src/PrimitiveRenderer.h +++ b/interface/src/PrimitiveRenderer.h @@ -74,7 +74,7 @@ public: /// Vertex element accessor. /// @return A list of vertex elements of the primitive /// - VertexElementList const & vertexElements() const; + const VertexElementList& vertexElements() const; /// Vertex element index accessor. /// @return A list of vertex element indices of the primitive @@ -103,7 +103,7 @@ private: /// Copy constructor prohibited. /// Primitive( - Primitive const & prim + const Primitive& prim ); // SPI methods are defined here @@ -112,7 +112,7 @@ private: /// Service implementer to provide private override for this method /// in derived class /// - virtual VertexElementList const & vVertexElements() const = 0; + virtual const VertexElementList& vVertexElements() const = 0; /// Vertex element index accessor. /// Service implementer to provide private override for this method @@ -166,10 +166,10 @@ private: /// Copy constructor prohibited. /// Cube ( - Cube const & cube + const Cube& cube ); - void initialize( + void init( float x, float y, float z, @@ -203,7 +203,7 @@ private: // SPI virtual override methods go here - VertexElementList const & vVertexElements() const; + const VertexElementList& vVertexElements() const; VertexElementIndexList& vVertexElementIndices(); TriElementList& vTriElements(); void vReleaseVertexElements(); @@ -275,7 +275,7 @@ private: /// Copy constructor prohibited. /// Renderer( - Renderer const & primitive + const Renderer& primitive ); // SPI methods are defined here @@ -341,10 +341,10 @@ private: /// Copy constructor prohibited. /// PrimitiveRenderer( - PrimitiveRenderer const & renderer + const PrimitiveRenderer& renderer ); - void initialize(); + void init(); void terminate(); /// Allocate and initialize GL buffers. From 0a7614ce21d715537ad5b1170e7942785785c803 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Thu, 13 Feb 2014 11:18:10 -0500 Subject: [PATCH 17/31] Fix compiler warnings on linux --- interface/src/PrimitiveRenderer.cpp | 42 ++++++++++++++++------------- interface/src/PrimitiveRenderer.h | 24 ++++++++--------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index 9da6d6b288..67f5a79a67 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -36,7 +36,7 @@ void Primitive::releaseVertexElements() { vReleaseVertexElements(); } -int Primitive::getMemoryUsage() { +unsigned long Primitive::getMemoryUsage() { return vGetMemoryUsage(); } @@ -225,7 +225,7 @@ void Cube::vReleaseVertexElements() { terminateVertices(); } -int Cube::vGetMemoryUsage() { +unsigned long Cube::vGetMemoryUsage() { return _cpuMemoryUsage; } @@ -310,11 +310,11 @@ void Renderer::render() { vRender(); } -int Renderer::getMemoryUsage() { +unsigned long Renderer::getMemoryUsage() { return vGetMemoryUsage(); } -int Renderer::getMemoryUsageGPU() { +unsigned long Renderer::getMemoryUsageGPU() { return vGetMemoryUsageGPU(); } @@ -322,15 +322,18 @@ PrimitiveRenderer::PrimitiveRenderer( int maxCount ) : _maxCount(maxCount), - _vertexElementCount(0), - _maxVertexElementCount(0), - _triElementCount(0), - _maxTriElementCount(0), - _primitiveCount(0), - _triBufferId(0), _vertexBufferId(0), + _vertexElementCount(0), + _maxVertexElementCount(0), + + _triElementCount(0), + _maxTriElementCount(0), + + _primitives(), + _primitiveCount(0), + _gpuMemoryUsage(0), _cpuMemoryUsage(0) @@ -412,9 +415,15 @@ void PrimitiveRenderer::terminate() { void PrimitiveRenderer::terminateGL() { - glDeleteBuffers(1, &_vertexBufferId); - glDeleteBuffers(1, &_triBufferId); - GLint err = glGetError(); + if (_vertexBufferId) { + glDeleteBuffers(1, &_vertexBufferId); + _vertexBufferId = 0; + } + + if (_triBufferId) { + glDeleteBuffers(1, &_triBufferId); + _triBufferId = 0; + } } void PrimitiveRenderer::terminateBookkeeping() { @@ -720,21 +729,18 @@ void PrimitiveRenderer::vRender() { glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexElement), (const GLvoid*)24); glBindBuffer(GL_ARRAY_BUFFER, 0); - GLint err = glGetError(); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triBufferId); glDrawElements(GL_TRIANGLES, 3 * _triElementCount, GL_UNSIGNED_INT, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glDisable(GL_CULL_FACE); - - err = glGetError(); } -int PrimitiveRenderer::vGetMemoryUsage() { +unsigned long PrimitiveRenderer::vGetMemoryUsage() { return _cpuMemoryUsage; } -int PrimitiveRenderer::vGetMemoryUsageGPU() { +unsigned long PrimitiveRenderer::vGetMemoryUsageGPU() { return _gpuMemoryUsage; } \ No newline at end of file diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/PrimitiveRenderer.h index a1b867c16a..f2f0ecea3f 100644 --- a/interface/src/PrimitiveRenderer.h +++ b/interface/src/PrimitiveRenderer.h @@ -92,7 +92,7 @@ public: /// Get memory usage. /// - int getMemoryUsage(); + unsigned long getMemoryUsage(); protected: /// Default constructor prohibited to API user, restricted to service implementer. @@ -136,7 +136,7 @@ private: /// Service implementer to provide private override for this method /// in derived class /// - virtual int vGetMemoryUsage() = 0; + virtual unsigned long vGetMemoryUsage() = 0; }; @@ -207,14 +207,14 @@ private: VertexElementIndexList& vVertexElementIndices(); TriElementList& vTriElements(); void vReleaseVertexElements(); - int vGetMemoryUsage(); + unsigned long vGetMemoryUsage(); private: VertexElementList _vertices; ///< Vertex element list VertexElementIndexList _vertexIndices; ///< Vertex element index list TriElementList _tris; ///< Tri element list - int _cpuMemoryUsage; ///< Memory allocation of object + unsigned long _cpuMemoryUsage; ///< Memory allocation of object static const int _sNumFacesPerCube = 6; static const int _sNumVerticesPerCube = 24; @@ -260,11 +260,11 @@ public: /// Get memory usage. /// - int getMemoryUsage(); + unsigned long getMemoryUsage(); /// Get GPU memory usage. /// - int getMemoryUsageGPU(); + unsigned long getMemoryUsageGPU(); protected: /// Default constructor prohibited to API user, restricted to service implementer. @@ -310,11 +310,11 @@ private: /// Get memory usage. /// - virtual int vGetMemoryUsage() = 0; + virtual unsigned long vGetMemoryUsage() = 0; /// Get GPU memory usage. /// - virtual int vGetMemoryUsageGPU() = 0; + virtual unsigned long vGetMemoryUsageGPU() = 0; }; @@ -439,11 +439,11 @@ private: /// Get memory usage. /// - int vGetMemoryUsage(); + unsigned long vGetMemoryUsage(); /// Get gpu memory usage. /// - int vGetMemoryUsageGPU(); + unsigned long vGetMemoryUsageGPU(); private: @@ -475,8 +475,8 @@ private: // Statistics parameters, not necessary for proper operation - int _gpuMemoryUsage; - int _cpuMemoryUsage; + unsigned long _gpuMemoryUsage; + unsigned long _cpuMemoryUsage; static const int _sIndicesPerTri = 3; From 11a399ec820be98e79399d92c0cbbea8fea94dff Mon Sep 17 00:00:00 2001 From: matsukaze Date: Thu, 13 Feb 2014 11:19:14 -0500 Subject: [PATCH 18/31] Fix crash bug Doh!! Renderer used before initialized. --- interface/src/VoxelSystem.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index a5e22fd1bb..990401d838 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -60,8 +60,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _treeScale(treeScale), _maxVoxels(maxVoxels), _initialized(false), - _inInspectForOcclusions(false), _showCulledSharedFaces(false), + _inInspectForOcclusions(false), _usePrimitiveRenderer(false), _renderer(0) { @@ -251,8 +251,6 @@ VoxelSystem::~VoxelSystem() { cleanupVoxelMemory(); delete _tree; - - _renderer = 0; } void VoxelSystem::setMaxVoxels(int maxVoxels) { @@ -371,8 +369,10 @@ void VoxelSystem::cleanupVoxelMemory() { _readColorsArray = NULL; _writeColorsArray = NULL; } + delete _renderer; _renderer = 0; + delete[] _writeVoxelDirtyArray; delete[] _readVoxelDirtyArray; _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL; @@ -1471,7 +1471,9 @@ void VoxelSystem::killLocalVoxels() { _tree->eraseAllOctreeElements(); _tree->unlock(); clearFreeBufferIndexes(); - _renderer->release(); + if (_renderer) { + _renderer->release(); + } _voxelsInReadArrays = 0; // do we need to do this? setupNewVoxelsForDrawing(); } @@ -1675,13 +1677,17 @@ void VoxelSystem::cullSharedFaces() { if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { _useVoxelShader = false; _usePrimitiveRenderer = true; - _renderer->release(); + if (_renderer) { + _renderer->release(); + } clearAllNodesBufferIndex(); inspectForOcclusions(); qDebug("culling shared faces in %d nodes", _nodeCount); } else { _usePrimitiveRenderer = false; - _renderer->release(); + if (_renderer) { + _renderer->release(); + } clearAllNodesBufferIndex(); _tree->lockForRead(); _tree->recurseTreeWithOperation(clearOcclusionsOperation); From a89f3bb9e57bace0e0ba1c36f6157035c2c18a72 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Thu, 13 Feb 2014 11:23:50 -0500 Subject: [PATCH 19/31] Fixes for style conformance --- libraries/octree/src/Octree.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 37534fdd7c..e0c7f414f8 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -208,12 +208,12 @@ public: OctreeElement* getOctreeElementAt(float x, float y, float z, float s) const; OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); - void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData=NULL); + void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL); - void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData=NULL); + void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData = NULL); void recurseTreeWithOperationDistanceSorted(RecurseOctreeOperation operation, - const glm::vec3& point, void* extraData=NULL); + const glm::vec3& point, void* extraData = NULL); int encodeTreeBitstream(OctreeElement* node, OctreePacketData* packetData, OctreeElementBag& bag, EncodeBitstreamParams& params) ; @@ -257,8 +257,8 @@ public: void recurseNodeWithOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData, int recursionCount = 0); - /** Traverse child nodes of node applying operation in post-fix order - */ + /// Traverse child nodes of node applying operation in post-fix order + /// void recurseNodeWithPostOperation(OctreeElement* node, RecurseOctreeOperation operation, void* extraData, int recursionCount = 0); From 6c50491ee755e8821c8d54cae397092cce7c69e2 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Thu, 13 Feb 2014 13:59:56 -0500 Subject: [PATCH 20/31] Fix compiler warnings on linux --- interface/src/PrimitiveRenderer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index 67f5a79a67..7f9866c369 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -384,8 +384,6 @@ void PrimitiveRenderer::initializeGL() { // Initialize the first vertex element in the buffer to all zeros, the // degenerate case deconstructVertexElement(0); - - GLint err = glGetError(); } void PrimitiveRenderer::initializeBookkeeping() { From 1f7f4d2a22984b1174eea3811873d9a1f8465db4 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Sun, 16 Feb 2014 23:25:06 -0500 Subject: [PATCH 21/31] Added id checking and remove try/catch --- interface/src/PrimitiveRenderer.cpp | 48 +++++++++++++---------------- interface/src/PrimitiveRenderer.h | 1 + 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/interface/src/PrimitiveRenderer.cpp b/interface/src/PrimitiveRenderer.cpp index 7f9866c369..7f3607e363 100644 --- a/interface/src/PrimitiveRenderer.cpp +++ b/interface/src/PrimitiveRenderer.cpp @@ -509,8 +509,10 @@ void PrimitiveRenderer::deconstructElements( for (TriElementList::const_iterator it = tris.begin(); it != tris.end(); ++it) { const TriElement* tri = *it; - // Put the tri element index into decon queue - _deconstructTriElementIndex.push(tri->id); + if (tri->id) { + // Put the tri element index into decon queue + _deconstructTriElementIndex.push(tri->id); + } } } @@ -522,8 +524,10 @@ void PrimitiveRenderer::deconstructElements( for (VertexElementIndexList::const_iterator it = vertexIndexList.begin(); it != vertexIndexList.end(); ++it) { int index = *it; - // Put the vertex element index into the available queue - _availableVertexElementIndex.push(index); + if (index) { + // Put the vertex element index into the available queue + _availableVertexElementIndex.push(index); + } } } @@ -633,42 +637,34 @@ int PrimitiveRenderer::vAdd( ) { QMutexLocker lock(&_guard); - int index = getAvailablePrimitiveIndex(); - if (index != 0) { - try { - // Take ownership of primitive, including responsibility - // for destruction - _primitives[index] = primitive; - _constructPrimitiveIndex.push(index); - _cpuMemoryUsage += primitive->getMemoryUsage(); - } catch(...) { - // Qt failed, recycle the index - _availablePrimitiveIndex.push(index); - index = 0; - } + int id = getAvailablePrimitiveIndex(); + if (id != 0) { + // Take ownership of primitive, including responsibility + // for destruction + _primitives[id] = primitive; + _constructPrimitiveIndex.push(id); + _cpuMemoryUsage += primitive->getMemoryUsage(); } - return index; + return id; } void PrimitiveRenderer::vRemove( - int index + int id ) { - try { + if (id != 0) { QMutexLocker lock(&_guard); // Locate and remove the primitive by id in the vector map - Primitive* primitive = _primitives[index]; + Primitive* primitive = _primitives[id]; if (primitive) { - _primitives[index] = 0; + _primitives[id] = 0; _cpuMemoryUsage -= primitive->getMemoryUsage(); deconstructElements(primitive); // Queue the index onto the available primitive stack. - _availablePrimitiveIndex.push(index); + _availablePrimitiveIndex.push(id); } - } catch(...) { - // Qt failed } } @@ -681,8 +677,8 @@ void PrimitiveRenderer::vRelease() { } void PrimitiveRenderer::vRender() { - int id; + int id; QMutexLocker lock(&_guard); // Iterate over the set of triangle element array buffer ids scheduled for diff --git a/interface/src/PrimitiveRenderer.h b/interface/src/PrimitiveRenderer.h index f2f0ecea3f..51d96e0840 100644 --- a/interface/src/PrimitiveRenderer.h +++ b/interface/src/PrimitiveRenderer.h @@ -283,6 +283,7 @@ private: /// Add primitive to renderer database. /// Service implementer to provide private override for this method /// in derived class + /// @return primitive id /// virtual int vAdd( Primitive* primitive ///< Pointer to primitive From 04b1c3e9359d92baa7f8e6158b69e1156d5d5592 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Sun, 16 Feb 2014 23:38:10 -0500 Subject: [PATCH 22/31] Fix occlusions between cousins. Recurse only to shouldRender or isLeaf voxel when inspecting for occlusions --- interface/src/VoxelSystem.cpp | 90 ++++++++++++++++++----------------- interface/src/VoxelSystem.h | 5 +- 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 990401d838..50e666b06c 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -61,7 +61,6 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _maxVoxels(maxVoxels), _initialized(false), _showCulledSharedFaces(false), - _inInspectForOcclusions(false), _usePrimitiveRenderer(false), _renderer(0) { @@ -1507,8 +1506,8 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; - // Nothing to do at the leaf level - if (voxel->isLeaf()) { + // Nothing to do at the leaf level or below the should render level + if (voxel->isLeaf() || voxel->getShouldRender()) { return false; } @@ -1526,11 +1525,6 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, // all faces which are completely covered by four child octants. unsigned char exteriorOcclusionsA = childA->getExteriorOcclusions(); - if (exteriorOcclusionsA == OctreeElement::HalfSpace::None) { - // There is nothing to be done with this child, next... - continue; - } - for (int j = i; --j >= 0; ) { VoxelTreeElement* childB = voxel->getChildAtIndex(j); @@ -1539,15 +1533,12 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, // Get child B's occluding faces unsigned char exteriorOcclusionsB = childB->getExteriorOcclusions(); - if (exteriorOcclusionsB == OctreeElement::HalfSpace::None) { - // There is nothing to be done with this child, next... - continue; - } - // Determine the shared halfspace partition between siblings A and B, // i.e., near/far, left/right, or top/bottom - unsigned char partition = _sOctantIndexToSharedBitMask[i][j] & - exteriorOcclusionsA & exteriorOcclusionsB; + unsigned char partitionA = _sOctantIndexToSharedBitMask[i][j] & + exteriorOcclusionsA; + unsigned char partitionB = _sOctantIndexToSharedBitMask[i][j] & + exteriorOcclusionsB; // Determine which face of each sibling is occluded. // Note the intentionally crossed indicies. It is necessary because @@ -1555,8 +1546,8 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, // example, if the near-left-top (NLT) and near-left-bottom (NLB) child voxels // exist, the shared partition is top-bottom (TB), and thus the occluded // shared face of the NLT voxel is its bottom face. - occludedSharedFace[i] |= (partition & _sOctantIndexToBitMask[j]); - occludedSharedFace[j] |= (partition & _sOctantIndexToBitMask[i]); + occludedSharedFace[i] |= (partitionB & _sOctantIndexToBitMask[j]); + occludedSharedFace[j] |= (partitionA & _sOctantIndexToBitMask[i]); } } // Combine this voxel's interior excluded shared face only to those children which are coincident @@ -1580,8 +1571,8 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; - // Nothing to do at the leaf level - if (voxel->isLeaf()) { + // Nothing to do at the leaf level or below the should render level + if (voxel->isLeaf() || voxel->getShouldRender()) { return false; } @@ -1594,7 +1585,8 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, VoxelTreeElement* child = voxel->getChildAtIndex(i); if (child) { - // Get the child's occluding faces, for a leaf, that will be + + // Get the child's occluding faces, for a leaf, that will be // all six voxel faces, and for a non leaf, that will be // all faces which are completely covered by four child octants. unsigned char exteriorOcclusionsOfChild = child->getExteriorOcclusions(); @@ -1648,12 +1640,12 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, return true; } -bool VoxelSystem::clearOcclusionsOperation(OctreeElement* element, void* extraData) { +bool VoxelSystem::clearAllOcclusionsOperation(OctreeElement* element, void* extraData) { _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; bool rc; - if (voxel->isLeaf()) { + if (voxel->isLeaf() || voxel->getShouldRender()) { // By definition the the exterior faces of a leaf voxel are // always occluders. @@ -1670,45 +1662,35 @@ bool VoxelSystem::clearOcclusionsOperation(OctreeElement* element, void* extraDa return rc; } - void VoxelSystem::cullSharedFaces() { - _nodeCount = 0; if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { _useVoxelShader = false; _usePrimitiveRenderer = true; + clearAllNodesBufferIndex(); if (_renderer) { _renderer->release(); } - clearAllNodesBufferIndex(); inspectForOcclusions(); - qDebug("culling shared faces in %d nodes", _nodeCount); } else { _usePrimitiveRenderer = false; + clearAllNodesBufferIndex(); if (_renderer) { _renderer->release(); } - clearAllNodesBufferIndex(); - _tree->lockForRead(); - _tree->recurseTreeWithOperation(clearOcclusionsOperation); - _tree->unlock(); - - - qDebug("unculling shared faces in %d nodes", _nodeCount); + clearAllOcclusions(); } - _writeRenderFullVBO = true; - _tree->setDirtyBit(); - setupNewVoxelsForDrawing(); - } void VoxelSystem::showCulledSharedFaces() { + _tree->lockForRead(); if (Menu::getInstance()->isOptionChecked(MenuOption::ShowCulledSharedFaces)) { _showCulledSharedFaces = true; } else { _showCulledSharedFaces = false; } + _tree->unlock(); if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { _writeRenderFullVBO = true; _tree->setDirtyBit(); @@ -1716,24 +1698,44 @@ void VoxelSystem::showCulledSharedFaces() { } } +void VoxelSystem::clearAllOcclusions() { + + _nodeCount = 0; + + bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showDebugDetails, "clearAllOcclusions()"); + + _tree->lockForRead(); + _tree->recurseTreeWithOperation(clearAllOcclusionsOperation); + _tree->unlock(); + + if (showDebugDetails) { + qDebug("clearing all occlusions of %d nodes", _nodeCount); + } + _writeRenderFullVBO = true; + _tree->setDirtyBit(); + setupNewVoxelsForDrawing(); +} + void VoxelSystem::inspectForOcclusions() { - // don't re-enter... - if (_inInspectForOcclusions) { - return; - } - - _inInspectForOcclusions = true; + _nodeCount = 0; bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showDebugDetails, "inspectForOcclusions()"); _tree->lockForRead(); _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); + _nodeCount = 0; _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); _tree->unlock(); - _inInspectForOcclusions = false; + if (showDebugDetails) { + qDebug("inspecting all occlusions of %d nodes", _nodeCount); + } + _writeRenderFullVBO = true; + _tree->setDirtyBit(); + setupNewVoxelsForDrawing(); } bool VoxelSystem::forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData) { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 62e9d2f903..8124a446ab 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -138,6 +138,7 @@ public slots: void falseColorizeBySource(); void forceRedrawEntireTree(); void clearAllNodesBufferIndex(); + void clearAllOcclusions(); void cullSharedFaces(); void showCulledSharedFaces(); @@ -196,7 +197,7 @@ private: static bool clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData); static bool inspectForExteriorOcclusionsOperation(OctreeElement* element, void* extraData); static bool inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData); - static bool clearOcclusionsOperation(OctreeElement* element, void* extraData); + static bool clearAllOcclusionsOperation(OctreeElement* element, void* extraData); static bool hideOutOfViewOperation(OctreeElement* element, void* extraData); static bool hideAllSubTreeOperation(OctreeElement* element, void* extraData); static bool showAllSubTreeOperation(OctreeElement* element, void* extraData); @@ -309,11 +310,11 @@ private: bool _inhideOutOfView; bool _showCulledSharedFaces; ///< Flag visibility of culled faces - bool _inInspectForOcclusions; ///< Flag occupancy of inspectForOcclusions method bool _usePrimitiveRenderer; ///< Flag primitive renderer for use PrimitiveRenderer* _renderer; ///< Voxel renderer static const int _sNumOctantsPerHemiVoxel = 4; + static int _sCorrectedChildIndex[8]; static unsigned char _sOctantIndexToBitMask[8]; ///< Map octant index to partition mask static unsigned char _sOctantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask From 32f0a81708bafc9843694e04a5779228ee0d9993 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Mon, 17 Feb 2014 00:27:24 -0500 Subject: [PATCH 23/31] Backed out last change to recursion. --- interface/src/VoxelSystem.cpp | 22 +++++++++++++++++----- interface/src/VoxelSystem.h | 1 + 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 50e666b06c..bed1c6b93b 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -60,6 +60,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _treeScale(treeScale), _maxVoxels(maxVoxels), _initialized(false), + _inOcclusions(false), _showCulledSharedFaces(false), _usePrimitiveRenderer(false), _renderer(0) { @@ -1506,8 +1507,8 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; - // Nothing to do at the leaf level or below the should render level - if (voxel->isLeaf() || voxel->getShouldRender()) { + // Nothing to do at the leaf level + if (voxel->isLeaf()) { return false; } @@ -1571,8 +1572,8 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; - // Nothing to do at the leaf level or below the should render level - if (voxel->isLeaf() || voxel->getShouldRender()) { + // Nothing to do at the leaf level + if (voxel->isLeaf()) { return false; } @@ -1645,7 +1646,7 @@ bool VoxelSystem::clearAllOcclusionsOperation(OctreeElement* element, void* extr VoxelTreeElement* voxel = (VoxelTreeElement*)element; bool rc; - if (voxel->isLeaf() || voxel->getShouldRender()) { + if (voxel->isLeaf()) { // By definition the the exterior faces of a leaf voxel are // always occluders. @@ -1700,6 +1701,10 @@ void VoxelSystem::showCulledSharedFaces() { void VoxelSystem::clearAllOcclusions() { + if (_inOcclusions) { + return; + } + _inOcclusions = true; _nodeCount = 0; bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); @@ -1715,10 +1720,16 @@ void VoxelSystem::clearAllOcclusions() { _writeRenderFullVBO = true; _tree->setDirtyBit(); setupNewVoxelsForDrawing(); + + _inOcclusions = false; } void VoxelSystem::inspectForOcclusions() { + if (_inOcclusions) { + return; + } + _inOcclusions = true; _nodeCount = 0; bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); @@ -1736,6 +1747,7 @@ void VoxelSystem::inspectForOcclusions() { _writeRenderFullVBO = true; _tree->setDirtyBit(); setupNewVoxelsForDrawing(); + _inOcclusions = false; } bool VoxelSystem::forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData) { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 8124a446ab..f90da5272f 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -309,6 +309,7 @@ private: bool _inhideOutOfView; + bool _inOcclusions; bool _showCulledSharedFaces; ///< Flag visibility of culled faces bool _usePrimitiveRenderer; ///< Flag primitive renderer for use PrimitiveRenderer* _renderer; ///< Voxel renderer From b838833c216c57e607287734e626494f4ec113d8 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Tue, 18 Feb 2014 08:00:30 -0500 Subject: [PATCH 24/31] Swizzle bit pairs in the occlusion bit mask --- interface/src/VoxelSystem.cpp | 99 ++++++++++++++++++++++++++++++----- interface/src/VoxelSystem.h | 1 + 2 files changed, 88 insertions(+), 12 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index bed1c6b93b..be1b319c22 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1542,15 +1542,17 @@ bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, exteriorOcclusionsB; // Determine which face of each sibling is occluded. - // Note the intentionally crossed indicies. It is necessary because - // the _sOctantIndexToBitMask is a partition occupancy mask. For + + // The _sOctantIndexToBitMask is a partition occupancy mask. For // example, if the near-left-top (NLT) and near-left-bottom (NLB) child voxels // exist, the shared partition is top-bottom (TB), and thus the occluded // shared face of the NLT voxel is its bottom face. - occludedSharedFace[i] |= (partitionB & _sOctantIndexToBitMask[j]); - occludedSharedFace[j] |= (partitionA & _sOctantIndexToBitMask[i]); + occludedSharedFace[i] |= (partitionB & _sOctantIndexToBitMask[i]); + occludedSharedFace[j] |= (partitionA & _sOctantIndexToBitMask[j]); } } + // Exchange bit pairs, left to right, vice versa, etc. + occludedSharedFace[i] = _sSwizzledOcclusionBits[occludedSharedFace[i]]; // Combine this voxel's interior excluded shared face only to those children which are coincident // with the excluded face. occludedSharedFace[i] |= (voxel->getInteriorOcclusions() & _sOctantIndexToBitMask[i]); @@ -1669,16 +1671,10 @@ void VoxelSystem::cullSharedFaces() { _useVoxelShader = false; _usePrimitiveRenderer = true; clearAllNodesBufferIndex(); - if (_renderer) { - _renderer->release(); - } inspectForOcclusions(); } else { _usePrimitiveRenderer = false; clearAllNodesBufferIndex(); - if (_renderer) { - _renderer->release(); - } clearAllOcclusions(); } } @@ -1693,6 +1689,9 @@ void VoxelSystem::showCulledSharedFaces() { } _tree->unlock(); if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { + if (_renderer) { + _renderer->release(); + } _writeRenderFullVBO = true; _tree->setDirtyBit(); setupNewVoxelsForDrawing(); @@ -1711,6 +1710,10 @@ void VoxelSystem::clearAllOcclusions() { PerformanceWarning warn(showDebugDetails, "clearAllOcclusions()"); _tree->lockForRead(); + if (_renderer) { + _renderer->release(); + } + _tree->recurseTreeWithOperation(clearAllOcclusionsOperation); _tree->unlock(); @@ -1736,15 +1739,19 @@ void VoxelSystem::inspectForOcclusions() { PerformanceWarning warn(showDebugDetails, "inspectForOcclusions()"); _tree->lockForRead(); + if (_renderer) { + _renderer->release(); + } + _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); _nodeCount = 0; _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); _tree->unlock(); - if (showDebugDetails) { + if (showDebugDetails) { qDebug("inspecting all occlusions of %d nodes", _nodeCount); } - _writeRenderFullVBO = true; + _writeRenderFullVBO = true; _tree->setDirtyBit(); setupNewVoxelsForDrawing(); _inOcclusions = false; @@ -3127,6 +3134,74 @@ unsigned long VoxelSystem::getVoxelMemoryUsageGPU() { return (_initialMemoryUsageGPU - currentFreeMemory); } +// Swizzle value of bit pairs of the value of index +unsigned short VoxelSystem::_sSwizzledOcclusionBits[64] = { + 0x0000, // 00000000 + 0x0002, // 00000001 + 0x0001, // 00000010 + 0x0003, // 00000011 + 0x0008, // 00000100 + 0x000a, // 00000101 + 0x0009, // 00000110 + 0x000b, // 00000111 + 0x0004, // 00001000 + 0x0006, // 00001001 + 0x0005, // 00001010 + 0x0007, // 00001011 + 0x000c, // 00001100 + 0x000e, // 00001101 + 0x000d, // 00001110 + 0x000f, // 00001111 + 0x0020, // 00010000 + 0x0022, // 00010001 + 0x0021, // 00010010 + 0x0023, // 00010011 + 0x0028, // 00010100 + 0x002a, // 00010101 + 0x0029, // 00010110 + 0x002b, // 00010111 + 0x0024, // 00011000 + 0x0026, // 00011001 + 0x0025, // 00011010 + 0x0027, // 00011011 + 0x002c, // 00011100 + 0x002e, // 00011101 + 0x002d, // 00011110 + 0x002f, // 00011111 + 0x0010, // 00100000 + 0x0012, // 00100001 + 0x0011, // 00100010 + 0x0013, // 00100011 + 0x0018, // 00100100 + 0x001a, // 00100101 + 0x0019, // 00100110 + 0x001b, // 00100111 + 0x0014, // 00101000 + 0x0016, // 00101001 + 0x0015, // 00101010 + 0x0017, // 00101011 + 0x001c, // 00101100 + 0x001e, // 00101101 + 0x001d, // 00101110 + 0x001f, // 00101111 + 0x0030, // 00110000 + 0x0032, // 00110001 + 0x0031, // 00110010 + 0x0033, // 00110011 + 0x0038, // 00110100 + 0x003a, // 00110101 + 0x0039, // 00110110 + 0x003b, // 00110111 + 0x0034, // 00111000 + 0x0036, // 00111001 + 0x0035, // 00111010 + 0x0037, // 00111011 + 0x003c, // 00111100 + 0x003e, // 00111101 + 0x003d, // 00111110 + 0x003f, // 00111111 +}; + // Octant bitmask array indexed by octant. The mask value indicates the octant's halfspace partitioning. The index // value corresponds to the voxel's octal code derived in "pointToVoxel" in SharedUtil.cpp, which, BTW, does *not* // correspond to the "ChildIndex" enum value in OctreeElement.h diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index f90da5272f..aadf549108 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -316,6 +316,7 @@ private: static const int _sNumOctantsPerHemiVoxel = 4; static int _sCorrectedChildIndex[8]; + static unsigned short _sSwizzledOcclusionBits[64]; ///< Swizzle value of bit pairs of the value of index static unsigned char _sOctantIndexToBitMask[8]; ///< Map octant index to partition mask static unsigned char _sOctantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask From 75ecdbd1f001b01283e19c25064b031d17f82540 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Wed, 19 Feb 2014 06:56:12 -0500 Subject: [PATCH 25/31] Merged clearAllOcclusions into inspectOcclusions --- interface/src/VoxelSystem.cpp | 107 +++++++++++++--------------------- interface/src/VoxelSystem.h | 4 +- 2 files changed, 42 insertions(+), 69 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index ab8196db24..a9abe1b99e 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -681,6 +681,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { if (_writeRenderFullVBO) { if (_usePrimitiveRenderer) { _renderer->release(); + clearAllNodesPrimitiveIndex(); } clearFreeBufferIndexes(); } @@ -1081,8 +1082,7 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelTreeElement* node) { node->setPrimitiveIndex(0); return 1; } - } - else { + } else { // if the node is not in the VBOs then we have nothing to do! if (node->isKnownBufferIndex()) { // If this node has not yet been written to the array, then add it to the end of the array. @@ -1585,8 +1585,11 @@ void VoxelSystem::killLocalVoxels() { _tree->eraseAllOctreeElements(); _tree->unlock(); clearFreeBufferIndexes(); - if (_renderer) { - _renderer->release(); + if (_usePrimitiveRenderer) { + if (_renderer) { + _renderer->release(); + } + clearAllNodesPrimitiveIndex(); } _voxelsInReadArrays = 0; // do we need to do this? setupNewVoxelsForDrawing(); @@ -1597,7 +1600,6 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; voxel->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); - voxel->setPrimitiveIndex(0); return true; } @@ -1616,6 +1618,28 @@ void VoxelSystem::clearAllNodesBufferIndex() { } } +// only called on main thread +bool VoxelSystem::clearAllNodesPrimitiveIndexOperation(OctreeElement* element, void* extraData) { + _nodeCount++; + VoxelTreeElement* voxel = (VoxelTreeElement*)element; + voxel->setPrimitiveIndex(0); + return true; +} + +// only called on main thread, and also always followed by a call to cleanupVoxelMemory() +// you shouldn't be calling this on any other thread or without also cleaning up voxel memory +void VoxelSystem::clearAllNodesPrimitiveIndex() { + PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), + "VoxelSystem::clearAllNodesPrimitiveIndex()"); + _nodeCount = 0; + _tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read + _tree->recurseTreeWithOperation(clearAllNodesPrimitiveIndexOperation); + _tree->unlock(); + if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { + qDebug("clearing primitive index of %d nodes", _nodeCount); + } +} + bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData) { _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; @@ -1689,7 +1713,15 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, // Nothing to do at the leaf level if (voxel->isLeaf()) { + // By definition the the exterior faces of a leaf voxel are + // always occluders. + voxel->setExteriorOcclusions(OctreeElement::HalfSpace::All); + // And the sibling occluders + voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); return false; + } else { + voxel->setExteriorOcclusions(OctreeElement::HalfSpace::None); + voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); } // Count of exterior occluding faces of this voxel element indexed @@ -1756,40 +1788,20 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element, return true; } -bool VoxelSystem::clearAllOcclusionsOperation(OctreeElement* element, void* extraData) { - _nodeCount++; - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - bool rc; - if (voxel->isLeaf()) { - - // By definition the the exterior faces of a leaf voxel are - // always occluders. - voxel->setExteriorOcclusions(OctreeElement::HalfSpace::All); - - // And the sibling occluders - voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); - rc = false; - } else { - voxel->setExteriorOcclusions(OctreeElement::HalfSpace::None); - voxel->setInteriorOcclusions(OctreeElement::HalfSpace::None); - rc = true; - } - - return rc; -} void VoxelSystem::cullSharedFaces() { if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { _useVoxelShader = false; _usePrimitiveRenderer = true; - clearAllNodesBufferIndex(); inspectForOcclusions(); } else { _usePrimitiveRenderer = false; clearAllNodesBufferIndex(); - clearAllOcclusions(); } + _writeRenderFullVBO = true; + _tree->setDirtyBit(); + setupNewVoxelsForDrawing(); } void VoxelSystem::showCulledSharedFaces() { @@ -1802,44 +1814,12 @@ void VoxelSystem::showCulledSharedFaces() { } _tree->unlock(); if (Menu::getInstance()->isOptionChecked(MenuOption::CullSharedFaces)) { - if (_renderer) { - _renderer->release(); - } _writeRenderFullVBO = true; _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } } -void VoxelSystem::clearAllOcclusions() { - - if (_inOcclusions) { - return; - } - _inOcclusions = true; - _nodeCount = 0; - - bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showDebugDetails, "clearAllOcclusions()"); - - _tree->lockForRead(); - if (_renderer) { - _renderer->release(); - } - - _tree->recurseTreeWithOperation(clearAllOcclusionsOperation); - _tree->unlock(); - - if (showDebugDetails) { - qDebug("clearing all occlusions of %d nodes", _nodeCount); - } - _writeRenderFullVBO = true; - _tree->setDirtyBit(); - setupNewVoxelsForDrawing(); - - _inOcclusions = false; -} - void VoxelSystem::inspectForOcclusions() { if (_inOcclusions) { @@ -1852,10 +1832,6 @@ void VoxelSystem::inspectForOcclusions() { PerformanceWarning warn(showDebugDetails, "inspectForOcclusions()"); _tree->lockForRead(); - if (_renderer) { - _renderer->release(); - } - _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); _nodeCount = 0; _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); @@ -1864,9 +1840,6 @@ void VoxelSystem::inspectForOcclusions() { if (showDebugDetails) { qDebug("inspecting all occlusions of %d nodes", _nodeCount); } - _writeRenderFullVBO = true; - _tree->setDirtyBit(); - setupNewVoxelsForDrawing(); _inOcclusions = false; } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 61b057b70a..42dc0c2ae0 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -137,7 +137,7 @@ public slots: void falseColorizeBySource(); void forceRedrawEntireTree(); void clearAllNodesBufferIndex(); - void clearAllOcclusions(); + void clearAllNodesPrimitiveIndex(); void cullSharedFaces(); void showCulledSharedFaces(); @@ -195,9 +195,9 @@ private: static bool killSourceVoxelsOperation(OctreeElement* element, void* extraData); static bool forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData); static bool clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData); + static bool clearAllNodesPrimitiveIndexOperation(OctreeElement* element, void* extraData); static bool inspectForExteriorOcclusionsOperation(OctreeElement* element, void* extraData); static bool inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData); - static bool clearAllOcclusionsOperation(OctreeElement* element, void* extraData); static bool hideOutOfViewOperation(OctreeElement* element, void* extraData); static bool hideAllSubTreeOperation(OctreeElement* element, void* extraData); static bool showAllSubTreeOperation(OctreeElement* element, void* extraData); From 4ee416ba96cf7408b9d921f6a8cc99480362018a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 19 Feb 2014 16:55:24 -0800 Subject: [PATCH 26/31] fixes for scripted avatars, closes #2033 --- assignment-client/src/Agent.cpp | 4 +++ assignment-client/src/Agent.h | 2 +- interface/src/Application.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 7 ---- interface/src/avatar/MyAvatar.h | 1 - libraries/avatars/src/AvatarData.cpp | 7 ++++ libraries/avatars/src/AvatarData.h | 5 +++ libraries/script-engine/src/ScriptEngine.cpp | 37 ++++++++++++++------ libraries/script-engine/src/ScriptEngine.h | 7 ++-- 9 files changed, 50 insertions(+), 22 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index cc0ddd59f2..015c3916ea 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -113,6 +113,10 @@ void Agent::run() { // setup an Avatar for the script to use AvatarData scriptedAvatar; + // call model URL setters with empty URLs so our avatar, if user, will have the default models + scriptedAvatar.setFaceModelURL(QUrl()); + scriptedAvatar.setSkeletonModelURL(QUrl()); + // give this AvatarData object to the script engine _scriptEngine.setAvatarData(&scriptedAvatar, "Avatar"); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index bc6b4f65fe..1502093d5b 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -29,7 +29,7 @@ class Agent : public ThreadedAssignment { public: Agent(const QByteArray& packet); - void setIsAvatar(bool isAvatar) { _scriptEngine.setIsAvatar(isAvatar); } + void setIsAvatar(bool isAvatar) { QMetaObject::invokeMethod(&_scriptEngine, "setIsAvatar", Q_ARG(bool, isAvatar)); } bool isAvatar() const { return _scriptEngine.isAvatar(); } public slots: diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ac45bf39d8..393cb39ec6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -252,7 +252,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : // send the identity packet for our avatar each second to our avatar mixer QTimer* identityPacketTimer = new QTimer(); connect(identityPacketTimer, &QTimer::timeout, _myAvatar, &MyAvatar::sendIdentityPacket); - identityPacketTimer->start(1000); + identityPacketTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 016159f415..8e91fc8c45 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -648,13 +648,6 @@ void MyAvatar::sendKillAvatar() { NodeList::getInstance()->broadcastToNodes(killPacket, NodeSet() << NodeType::AvatarMixer); } -void MyAvatar::sendIdentityPacket() { - QByteArray identityPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarIdentity); - identityPacket.append(AvatarData::identityByteArray()); - - NodeList::getInstance()->broadcastToNodes(identityPacket, NodeSet() << NodeType::AvatarMixer); -} - void MyAvatar::orbit(const glm::vec3& position, int deltaX, int deltaY) { // first orbit horizontally glm::quat orientation = getOrientation(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1bc5de204b..538ca4e0b2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -89,7 +89,6 @@ public slots: void increaseSize(); void decreaseSize(); void resetSize(); - void sendIdentityPacket(); // Set/Get update the thrust that will move the avatar around void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 8e9eb430e8..e40adbc0df 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -338,3 +338,10 @@ void AvatarData::setOrientation(const glm::quat& orientation) { _bodyYaw = eulerAngles.y; _bodyRoll = eulerAngles.z; } + +void AvatarData::sendIdentityPacket() { + QByteArray identityPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarIdentity); + identityPacket.append(identityByteArray()); + + NodeList::getInstance()->broadcastToNodes(identityPacket, NodeSet() << NodeType::AvatarMixer); +} \ No newline at end of file diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a889b52bd0..6e95c1c29d 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -52,6 +52,8 @@ static const float MIN_AVATAR_SCALE = .005f; const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation +const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000; + const QUrl DEFAULT_HEAD_MODEL_URL = QUrl("http://public.highfidelity.io/meshes/defaultAvatar_head.fst"); const QUrl DEFAULT_BODY_MODEL_URL = QUrl("http://public.highfidelity.io/meshes/defaultAvatar_body.fst"); @@ -157,6 +159,9 @@ public: virtual float getBoundingRadius() const { return 1.f; } +public slots: + void sendIdentityPacket(); + protected: glm::vec3 _position; glm::vec3 _handPosition; diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 5c089b9a74..1efda7cfe3 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -44,6 +44,7 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co AbstractMenuInterface* menu, AbstractControllerScriptingInterface* controllerScriptingInterface) : _isAvatar(false), + _avatarIdentityTimer(NULL), _avatarData(NULL) { _scriptContents = scriptContents; @@ -74,6 +75,21 @@ ScriptEngine::~ScriptEngine() { //printf("ScriptEngine::~ScriptEngine()...\n"); } +void ScriptEngine::setIsAvatar(bool isAvatar) { + _isAvatar = isAvatar; + + if (_isAvatar && !_avatarIdentityTimer) { + // set up the avatar identity timer + _avatarIdentityTimer = new QTimer(this); + + // connect our slot + connect(_avatarIdentityTimer, &QTimer::timeout, this, &ScriptEngine::sendAvatarIdentityPacket); + + // start the timer + _avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); + } +} + void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectName) { _avatarData = avatarData; @@ -84,6 +100,7 @@ void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectNa registerGlobalObject(objectName, _avatarData); } + void ScriptEngine::setupMenuItems() { if (_menu && _wantMenuItems) { _menu->addActionToQMenuAndActionHash(_menu->getActiveScriptsMenu(), _scriptMenuName, 0, this, SLOT(stop())); @@ -173,6 +190,12 @@ void ScriptEngine::evaluate() { } } +void ScriptEngine::sendAvatarIdentityPacket() { + if (_isAvatar && _avatarData) { + _avatarData->sendIdentityPacket(); + } +} + void ScriptEngine::run() { if (!_isInitialized) { init(); @@ -229,16 +252,7 @@ void ScriptEngine::run() { } if (_isAvatar && _avatarData) { - static QByteArray avatarPacket; - int numAvatarHeaderBytes = 0; - - if (avatarPacket.size() == 0) { - // pack the avatar header bytes the first time - // unlike the _avatar.getBroadcastData these won't change - numAvatarHeaderBytes = populatePacketHeader(avatarPacket, PacketTypeAvatarData); - } - - avatarPacket.resize(numAvatarHeaderBytes); + QByteArray avatarPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarData); avatarPacket.append(_avatarData->toByteArray()); nodeList->broadcastToNodes(avatarPacket, NodeSet() << NodeType::AvatarMixer); @@ -253,6 +267,9 @@ void ScriptEngine::run() { } emit scriptEnding(); + // kill the avatar identity timer + delete _avatarIdentityTimer; + if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) { // release the queue of edit voxel messages. _voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 3de16348d4..cf5ad1a68b 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -11,9 +11,9 @@ #include -#include #include #include +#include #include #include @@ -52,7 +52,7 @@ public: void registerGlobalObject(const QString& name, QObject* object); /// registers a global object by name - void setIsAvatar(bool isAvatar) { _isAvatar = isAvatar; } + Q_INVOKABLE void setIsAvatar(bool isAvatar); bool isAvatar() const { return _isAvatar; } void setAvatarData(AvatarData* avatarData, const QString& objectName); @@ -84,9 +84,12 @@ protected: bool _isInitialized; QScriptEngine _engine; bool _isAvatar; + QTimer* _avatarIdentityTimer; QHash _timerFunctionMap; private: + void sendAvatarIdentityPacket(); + QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); From ee9f8937e3082ec28806768ed07b2ca313e82f3e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 19 Feb 2014 18:03:34 -0800 Subject: [PATCH 27/31] fix a silly typo --- assignment-client/src/avatars/AvatarMixer.cpp | 6 +++--- data-server/src/DataServer.cpp | 4 ++-- domain-server/src/DomainServer.cpp | 4 ++-- interface/src/Application.cpp | 2 +- interface/src/MetavoxelSystem.cpp | 2 +- interface/src/avatar/AvatarManager.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 2 +- libraries/audio/src/AudioInjector.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 2 +- libraries/shared/src/DataServerClient.cpp | 4 ++-- libraries/shared/src/NodeList.cpp | 8 ++++---- libraries/shared/src/PacketHeaders.cpp | 2 +- libraries/shared/src/PacketHeaders.h | 2 +- 14 files changed, 22 insertions(+), 22 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index c7989bc9e9..63bdccbab7 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -93,7 +93,7 @@ void broadcastIdentityPacket() { NodeList* nodeList = NodeList::getInstance(); - QByteArray avatarIdentityPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarIdentity); + QByteArray avatarIdentityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); int numPacketHeaderBytes = avatarIdentityPacket.size(); foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { @@ -128,7 +128,7 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { && killedNode->getLinkedData()) { // this was an avatar we were sending to other people // send a kill packet for it to our other nodes - QByteArray killPacket = byteArrayWithPopluatedHeader(PacketTypeKillAvatar); + QByteArray killPacket = byteArrayWithPopulatedHeader(PacketTypeKillAvatar); killPacket += killedNode->getUUID().toRfc4122(); NodeList::getInstance()->broadcastToNodes(killPacket, @@ -159,7 +159,7 @@ void AvatarMixer::readPendingDatagrams() { if (nodeData->hasIdentityChangedAfterParsing(receivedPacket) && !nodeData->hasSentIdentityBetweenKeyFrames()) { // this avatar changed their identity in some way and we haven't sent a packet in this keyframe - QByteArray identityPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarIdentity); + QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); QByteArray individualByteArray = nodeData->identityByteArray(); individualByteArray.replace(0, NUM_BYTES_RFC4122_UUID, avatarNode->getUUID().toRfc4122()); diff --git a/data-server/src/DataServer.cpp b/data-server/src/DataServer.cpp index 97228b67a3..76386d7b5a 100644 --- a/data-server/src/DataServer.cpp +++ b/data-server/src/DataServer.cpp @@ -121,7 +121,7 @@ void DataServer::readPendingDatagrams() { if (reply->type == REDIS_REPLY_STATUS && strcmp("OK", reply->str) == 0) { // if redis stored the value successfully reply back with a confirm // which is a reply packet with the sequence number - QByteArray replyPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerConfirm, _uuid); + QByteArray replyPacket = byteArrayWithPopulatedHeader(PacketTypeDataServerConfirm, _uuid); replyPacket.append(sequenceNumber); @@ -132,7 +132,7 @@ void DataServer::readPendingDatagrams() { } else { // setup a send packet with the returned data // leverage the packetData sent by overwriting and appending - QByteArray sendPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerSend, _uuid); + QByteArray sendPacket = byteArrayWithPopulatedHeader(PacketTypeDataServerSend, _uuid); QDataStream sendPacketStream(&sendPacket, QIODevice::Append); sendPacketStream << sequenceNumber; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 896b709e2a..e9816abe4c 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -221,10 +221,10 @@ void DomainServer::readAvailableDatagrams() { HifiSockAddr senderSockAddr, nodePublicAddress, nodeLocalAddress; - static QByteArray broadcastPacket = byteArrayWithPopluatedHeader(PacketTypeDomainList); + static QByteArray broadcastPacket = byteArrayWithPopulatedHeader(PacketTypeDomainList); static int numBroadcastPacketHeaderBytes = broadcastPacket.size(); - static QByteArray assignmentPacket = byteArrayWithPopluatedHeader(PacketTypeCreateAssignment); + static QByteArray assignmentPacket = byteArrayWithPopulatedHeader(PacketTypeCreateAssignment); static int numAssignmentPacketHeaderBytes = assignmentPacket.size(); QByteArray receivedPacket; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 393cb39ec6..73d13750bb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2376,7 +2376,7 @@ void Application::updateMyAvatar(float deltaTime) { _myAvatar->update(deltaTime); // send head/hand data to the avatar mixer and voxel server - QByteArray packet = byteArrayWithPopluatedHeader(PacketTypeAvatarData); + QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData); packet.append(_myAvatar->toByteArray()); controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer); diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 34c3be5308..3ed62cdb14 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -180,7 +180,7 @@ bool MetavoxelSystem::PointVisitor::visit(MetavoxelInfo& info) { } static QByteArray createDatagramHeader(const QUuid& sessionID) { - QByteArray header = byteArrayWithPopluatedHeader(PacketTypeMetavoxelData); + QByteArray header = byteArrayWithPopulatedHeader(PacketTypeMetavoxelData); header += sessionID.toRfc4122(); return header; } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 4cc568cf18..b873b10017 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -144,7 +144,7 @@ void AvatarManager::processAvatarMixerDatagram(const QByteArray& datagram, const void AvatarManager::processAvatarDataPacket(const QByteArray &datagram, const QWeakPointer &mixerWeakPointer) { int bytesRead = numBytesForPacketHeader(datagram); - QByteArray dummyAvatarByteArray = byteArrayWithPopluatedHeader(PacketTypeAvatarData); + QByteArray dummyAvatarByteArray = byteArrayWithPopulatedHeader(PacketTypeAvatarData); int numDummyHeaderBytes = dummyAvatarByteArray.size(); int numDummyHeaderBytesWithoutUUID = numDummyHeaderBytes - NUM_BYTES_RFC4122_UUID; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8e91fc8c45..90ef18848b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -644,7 +644,7 @@ void MyAvatar::loadData(QSettings* settings) { } void MyAvatar::sendKillAvatar() { - QByteArray killPacket = byteArrayWithPopluatedHeader(PacketTypeKillAvatar); + QByteArray killPacket = byteArrayWithPopulatedHeader(PacketTypeKillAvatar); NodeList::getInstance()->broadcastToNodes(killPacket, NodeSet() << NodeType::AvatarMixer); } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index ff243459b7..2d4074f125 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -47,7 +47,7 @@ void AudioInjector::injectAudio() { NodeList* nodeList = NodeList::getInstance(); // setup the packet for injected audio - QByteArray injectAudioPacket = byteArrayWithPopluatedHeader(PacketTypeInjectAudio); + QByteArray injectAudioPacket = byteArrayWithPopulatedHeader(PacketTypeInjectAudio); QDataStream packetStream(&injectAudioPacket, QIODevice::Append); packetStream << QUuid::createUuid(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e40adbc0df..296b91ce2f 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -340,7 +340,7 @@ void AvatarData::setOrientation(const glm::quat& orientation) { } void AvatarData::sendIdentityPacket() { - QByteArray identityPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarIdentity); + QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); identityPacket.append(identityByteArray()); NodeList::getInstance()->broadcastToNodes(identityPacket, NodeSet() << NodeType::AvatarMixer); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 1efda7cfe3..076f941222 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -252,7 +252,7 @@ void ScriptEngine::run() { } if (_isAvatar && _avatarData) { - QByteArray avatarPacket = byteArrayWithPopluatedHeader(PacketTypeAvatarData); + QByteArray avatarPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarData); avatarPacket.append(_avatarData->toByteArray()); nodeList->broadcastToNodes(avatarPacket, NodeSet() << NodeType::AvatarMixer); diff --git a/libraries/shared/src/DataServerClient.cpp b/libraries/shared/src/DataServerClient.cpp index fd003aa3bb..8903aa0524 100644 --- a/libraries/shared/src/DataServerClient.cpp +++ b/libraries/shared/src/DataServerClient.cpp @@ -31,7 +31,7 @@ const HifiSockAddr& DataServerClient::dataServerSockAddr() { void DataServerClient::putValueForKeyAndUserString(const QString& key, const QString& value, const QString& userString) { // setup the header for this packet and push packetStream to desired spot - QByteArray putPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerPut); + QByteArray putPacket = byteArrayWithPopulatedHeader(PacketTypeDataServerPut); QDataStream packetStream(&putPacket, QIODevice::Append); // pack our data for the put packet @@ -66,7 +66,7 @@ void DataServerClient::getValuesForKeysAndUUID(const QStringList& keys, const QU void DataServerClient::getValuesForKeysAndUserString(const QStringList& keys, const QString& userString, DataServerCallbackObject* callbackObject) { if (!userString.isEmpty() && keys.size() <= UCHAR_MAX) { - QByteArray getPacket = byteArrayWithPopluatedHeader(PacketTypeDataServerGet); + QByteArray getPacket = byteArrayWithPopulatedHeader(PacketTypeDataServerGet); QDataStream packetStream(&getPacket, QIODevice::Append); // pack our data for the getPacket diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 8dd3857198..bd43c5d2d9 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -528,7 +528,7 @@ void NodeList::sendDomainServerCheckIn() { // construct the DS check in packet if we can // check in packet has header, optional UUID, node type, port, IP, node types of interest, null termination - QByteArray domainServerPacket = byteArrayWithPopluatedHeader(PacketTypeDomainListRequest); + QByteArray domainServerPacket = byteArrayWithPopulatedHeader(PacketTypeDomainListRequest); QDataStream packetStream(&domainServerPacket, QIODevice::Append); // pack our data to send to the domain-server @@ -616,7 +616,7 @@ void NodeList::sendAssignment(Assignment& assignment) { ? PacketTypeCreateAssignment : PacketTypeRequestAssignment; - QByteArray packet = byteArrayWithPopluatedHeader(assignmentPacketType); + QByteArray packet = byteArrayWithPopulatedHeader(assignmentPacketType); QDataStream packetStream(&packet, QIODevice::Append); packetStream << assignment; @@ -631,7 +631,7 @@ void NodeList::sendAssignment(Assignment& assignment) { } QByteArray NodeList::constructPingPacket(PingType_t pingType) { - QByteArray pingPacket = byteArrayWithPopluatedHeader(PacketTypePing); + QByteArray pingPacket = byteArrayWithPopulatedHeader(PacketTypePing); QDataStream packetStream(&pingPacket, QIODevice::Append); @@ -651,7 +651,7 @@ QByteArray NodeList::constructPingReplyPacket(const QByteArray& pingPacket) { quint64 timeFromOriginalPing; pingPacketStream >> timeFromOriginalPing; - QByteArray replyPacket = byteArrayWithPopluatedHeader(PacketTypePingReply); + QByteArray replyPacket = byteArrayWithPopulatedHeader(PacketTypePingReply); QDataStream packetStream(&replyPacket, QIODevice::Append); packetStream << typeFromOriginalPing << timeFromOriginalPing << usecTimestampNow(); diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index b1f6ef1730..69178d7bd5 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -65,7 +65,7 @@ PacketVersion versionForPacketType(PacketType type) { } } -QByteArray byteArrayWithPopluatedHeader(PacketType type, const QUuid& connectionUUID) { +QByteArray byteArrayWithPopulatedHeader(PacketType type, const QUuid& connectionUUID) { QByteArray freshByteArray(MAX_PACKET_HEADER_BYTES, 0); freshByteArray.resize(populatePacketHeader(freshByteArray, type, connectionUUID)); return freshByteArray; diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index c1a5a34114..c7496b7f4a 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -66,7 +66,7 @@ PacketVersion versionForPacketType(PacketType type); const QUuid nullUUID = QUuid(); -QByteArray byteArrayWithPopluatedHeader(PacketType type, const QUuid& connectionUUID = nullUUID); +QByteArray byteArrayWithPopulatedHeader(PacketType type, const QUuid& connectionUUID = nullUUID); int populatePacketHeader(QByteArray& packet, PacketType type, const QUuid& connectionUUID = nullUUID); int populatePacketHeader(char* packet, PacketType type, const QUuid& connectionUUID = nullUUID); From b81343830754e94b13662f4f1f812c29ea587587 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Thu, 20 Feb 2014 08:48:40 -0500 Subject: [PATCH 28/31] Consolidate primitive index with buffer index. Removed the extra space associated with primitive index and use buffer index for both the VBO and primitive renderers since they are exclusive. --- interface/src/VoxelSystem.cpp | 52 +++++++------------------ interface/src/VoxelSystem.h | 2 - libraries/voxels/src/VoxelTreeElement.h | 3 -- 3 files changed, 15 insertions(+), 42 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index a9abe1b99e..ac27ac3209 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -681,7 +681,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { if (_writeRenderFullVBO) { if (_usePrimitiveRenderer) { _renderer->release(); - clearAllNodesPrimitiveIndex(); + clearAllNodesBufferIndex(); } clearFreeBufferIndexes(); } @@ -1076,10 +1076,10 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelTreeElement* node) { } if (_usePrimitiveRenderer) { - int primitiveIndex = node->getPrimitiveIndex(); - if (primitiveIndex) { + if (node->isKnownBufferIndex()) { + int primitiveIndex = node->getBufferIndex(); _renderer->remove(primitiveIndex); - node->setPrimitiveIndex(0); + node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); return 1; } } else { @@ -1123,10 +1123,10 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo nodeColor const & color = node->getColor(); if (_usePrimitiveRenderer) { - int primitiveIndex = node->getPrimitiveIndex(); - if (primitiveIndex) { + if (node->isKnownBufferIndex()) { + int primitiveIndex = node->getBufferIndex(); _renderer->remove(primitiveIndex); - node->setPrimitiveIndex(0); + node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); } else { node->setVoxelSystem(this); } @@ -1142,8 +1142,8 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX], occlusions); if (cube) { - primitiveIndex = _renderer->add(cube); - node->setPrimitiveIndex(primitiveIndex); + int primitiveIndex = _renderer->add(cube); + node->setBufferIndex(primitiveIndex); } } } else { @@ -1589,7 +1589,7 @@ void VoxelSystem::killLocalVoxels() { if (_renderer) { _renderer->release(); } - clearAllNodesPrimitiveIndex(); + clearAllNodesBufferIndex(); } _voxelsInReadArrays = 0; // do we need to do this? setupNewVoxelsForDrawing(); @@ -1618,28 +1618,6 @@ void VoxelSystem::clearAllNodesBufferIndex() { } } -// only called on main thread -bool VoxelSystem::clearAllNodesPrimitiveIndexOperation(OctreeElement* element, void* extraData) { - _nodeCount++; - VoxelTreeElement* voxel = (VoxelTreeElement*)element; - voxel->setPrimitiveIndex(0); - return true; -} - -// only called on main thread, and also always followed by a call to cleanupVoxelMemory() -// you shouldn't be calling this on any other thread or without also cleaning up voxel memory -void VoxelSystem::clearAllNodesPrimitiveIndex() { - PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), - "VoxelSystem::clearAllNodesPrimitiveIndex()"); - _nodeCount = 0; - _tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read - _tree->recurseTreeWithOperation(clearAllNodesPrimitiveIndexOperation); - _tree->unlock(); - if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { - qDebug("clearing primitive index of %d nodes", _nodeCount); - } -} - bool VoxelSystem::inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData) { _nodeCount++; VoxelTreeElement* voxel = (VoxelTreeElement*)element; @@ -2421,7 +2399,7 @@ bool VoxelSystem::hideAllSubTreeOperation(OctreeElement* element, void* extraDat } args->nodesOutside++; - if (voxel->isKnownBufferIndex() || voxel->getPrimitiveIndex()) { + if (voxel->isKnownBufferIndex()) { args->nodesRemoved++; bool falseColorize = false; if (falseColorize) { @@ -2463,7 +2441,7 @@ bool VoxelSystem::showAllSubTreeOperation(OctreeElement* element, void* extraDat bool shouldRender = voxel->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale, boundaryLevelAdjust); voxel->setShouldRender(shouldRender); - if (shouldRender && !(voxel->isKnownBufferIndex() || voxel->getPrimitiveIndex())) { + if (shouldRender && !voxel->isKnownBufferIndex()) { bool falseColorize = false; if (falseColorize) { voxel->setFalseColor(0,0,255); // false colorize @@ -2558,7 +2536,7 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData // if the child node INTERSECTs the view, then we want to check to see if it thinks it should render // if it should render but is missing it's VBO index, then we want to flip it on, and we can stop recursing from // here because we know will block any children anyway - if (voxel->getShouldRender() && !(voxel->isKnownBufferIndex() || voxel->getPrimitiveIndex())) { + if (voxel->getShouldRender() && !voxel->isKnownBufferIndex()) { voxel->setDirtyBit(); // will this make it draw? args->nodesShown++; return false; @@ -2722,9 +2700,9 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v } unsigned long nodeIndex = 0; - if (voxel->getPrimitiveIndex()) { + if (voxel->getBufferIndex()) { args->nodesInPrimitiveRenderer++; - nodeIndex = voxel->getPrimitiveIndex(); + nodeIndex = voxel->getBufferIndex(); const bool extraDebugging = false; // enable for extra debugging if (extraDebugging) { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 42dc0c2ae0..0e2ae29475 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -137,7 +137,6 @@ public slots: void falseColorizeBySource(); void forceRedrawEntireTree(); void clearAllNodesBufferIndex(); - void clearAllNodesPrimitiveIndex(); void cullSharedFaces(); void showCulledSharedFaces(); @@ -195,7 +194,6 @@ private: static bool killSourceVoxelsOperation(OctreeElement* element, void* extraData); static bool forceRedrawEntireTreeOperation(OctreeElement* element, void* extraData); static bool clearAllNodesBufferIndexOperation(OctreeElement* element, void* extraData); - static bool clearAllNodesPrimitiveIndexOperation(OctreeElement* element, void* extraData); static bool inspectForExteriorOcclusionsOperation(OctreeElement* element, void* extraData); static bool inspectForInteriorOcclusionsOperation(OctreeElement* element, void* extraData); static bool hideOutOfViewOperation(OctreeElement* element, void* extraData); diff --git a/libraries/voxels/src/VoxelTreeElement.h b/libraries/voxels/src/VoxelTreeElement.h index 15ee5c7c76..83544bea32 100644 --- a/libraries/voxels/src/VoxelTreeElement.h +++ b/libraries/voxels/src/VoxelTreeElement.h @@ -49,8 +49,6 @@ public: - int getPrimitiveIndex() const { return _primitiveIndex; } - void setPrimitiveIndex(int index) { _primitiveIndex = index; } glBufferIndex getBufferIndex() const { return _glBufferIndex; } bool isKnownBufferIndex() const { return !_unknownBufferIndex; } void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; _unknownBufferIndex =(index == GLBUFFER_INDEX_UNKNOWN);} @@ -98,7 +96,6 @@ protected: nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes private: - int _primitiveIndex; ///< Unique identifier given by PrimitiveRenderer unsigned char _exteriorOcclusions; ///< Exterior shared partition boundaries that are completely occupied unsigned char _interiorOcclusions; ///< Interior shared partition boundaries with siblings }; From 4fbe8acd1e2476e9d612b5a567d6171f0e44d365 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 20 Feb 2014 11:12:53 -0800 Subject: [PATCH 29/31] fix face and skeleton model URL Q_PROPERTY macros --- libraries/avatars/src/AvatarData.cpp | 1 - libraries/avatars/src/AvatarData.h | 11 +++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 296b91ce2f..8566958349 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -323,7 +323,6 @@ void AvatarData::setDisplayName(const QString& displayName) { qDebug() << "Changing display name for avatar to" << displayName; } - void AvatarData::setClampedTargetScale(float targetScale) { targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 6e95c1c29d..ad95d021ce 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -82,8 +82,8 @@ class AvatarData : public NodeData { Q_PROPERTY(float audioLoudness READ getAudioLoudness WRITE setAudioLoudness) Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness) - Q_PROPERTY(QUrl faceModelURL READ getFaceModelURL WRITE setFaceModelURL) - Q_PROPERTY(QUrl skeletonModelURL READ getSkeletonModelURL WRITE setSkeletonModelURL) + Q_PROPERTY(QString faceModelURL READ getFaceModelURLFromScript WRITE setFaceModelURLFromScript) + Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript) public: AvatarData(); ~AvatarData(); @@ -151,12 +151,19 @@ public: QByteArray identityByteArray(); const QUrl& getFaceModelURL() const { return _faceModelURL; } + QString getFaceModelURLString() const { return _faceModelURL.toString(); } const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; } const QString& getDisplayName() const { return _displayName; } virtual void setFaceModelURL(const QUrl& faceModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setDisplayName(const QString& displayName); + QString getFaceModelURLFromScript() const { return _faceModelURL.toString(); } + void setFaceModelURLFromScript(const QString& faceModelString) { setFaceModelURL(faceModelString); } + + QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); } + void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); } + virtual float getBoundingRadius() const { return 1.f; } public slots: From 2626d7db8c1709419f2f5ca3e97361fbf93ac110 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 20 Feb 2014 11:14:50 -0800 Subject: [PATCH 30/31] add a bot example script --- examples/bot.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 examples/bot.js diff --git a/examples/bot.js b/examples/bot.js new file mode 100644 index 0000000000..6d0abd740e --- /dev/null +++ b/examples/bot.js @@ -0,0 +1,34 @@ +// +// bot.js +// hifi +// +// Created by Brad Hefta-Gaub on 2/20/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates an NPC avatar. +// +// + +function getRandomFloat(min, max) { + return Math.random() * (max - min) + min; +} + +function getRandomInt (min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +// choose a random x and y in the range of 0 to 50 +positionX = getRandomFloat(0, 50); +positionZ = getRandomFloat(0, 50); + +// change the avatar's position to the random one +Avatar.position = {x: positionX, y: 0, z: positionZ}; + +// pick an integer between 1 and 20 for the face model for this bot +botNumber = getRandomInt(1, 20); + +// set the face model fst using the bot number +// there is no need to change the body model - we're using the default +Avatar.faceModelURL = "https://s3-us-west-1.amazonaws.com/highfidelity-public/meshes/bot" + botNumber + ".fst"; + +Agent.isAvatar = true; \ No newline at end of file From 943b0b1b1579d938ee2bec7a16ae7365e401e8f7 Mon Sep 17 00:00:00 2001 From: matsukaze Date: Thu, 20 Feb 2014 23:30:29 -0500 Subject: [PATCH 31/31] Removed primitiveIndex --- libraries/voxels/src/VoxelTreeElement.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTreeElement.cpp b/libraries/voxels/src/VoxelTreeElement.cpp index f1a7883df5..3f8af58afd 100644 --- a/libraries/voxels/src/VoxelTreeElement.cpp +++ b/libraries/voxels/src/VoxelTreeElement.cpp @@ -15,7 +15,6 @@ VoxelTreeElement::VoxelTreeElement(unsigned char* octalCode) : OctreeElement(), - _primitiveIndex(0), _exteriorOcclusions(OctreeElement::HalfSpace::All), _interiorOcclusions(OctreeElement::HalfSpace::None) {