1579 lines · 58.7 KB · C++
RawDownload
    _setupNewVoxelsForDrawingLastElapsed = 0;    _lastViewCullingElapsed = _lastViewCulling = 0;     // When we change voxels representations in the arrays, we'll update this    _voxelsDirty = false;    _voxelsInWriteArrays = 0;    _voxelsInReadArrays = 0;     // we will track individual dirty sections with these arrays of bools    _writeVoxelDirtyArray = new bool[_maxVoxels];    memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool));    _readVoxelDirtyArray = new bool[_maxVoxels];    memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool));     // prep the data structures for incoming voxel data    _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels];    _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels];     _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels];    _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels];     GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * _maxVoxels];     // populate the indicesArray    // this will not change given new voxels, so we can set it all up now    for (int n = 0; n < _maxVoxels; n++) {        // fill the indices array        int voxelIndexOffset = n * INDICES_PER_VOXEL;        GLuint* currentIndicesPos = indicesArray + voxelIndexOffset;        int startIndex = (n * VERTICES_PER_VOXEL);         for (int i = 0; i < INDICES_PER_VOXEL; i++) {            // add indices for this side of the cube            currentIndicesPos[i] = startIndex + identityIndices[i];        }    }     GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels];    GLfloat* normalsArrayEndPointer = normalsArray;     // populate the normalsArray    for (int n = 0; n < _maxVoxels; n++) {        for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) {            *(normalsArrayEndPointer++) = identityNormals[i];        }    }     // VBO for the verticesArray    glGenBuffers(1, &_vboVerticesID);    glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);    glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);     // VBO for the normalsArray    glGenBuffers(1, &_vboNormalsID);    glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);    glBufferData(GL_ARRAY_BUFFER,                 VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels,                 normalsArray, GL_STATIC_DRAW);     // VBO for colorsArray    glGenBuffers(1, &_vboColorsID);    glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);    glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);     // VBO for the indicesArray    glGenBuffers(1, &_vboIndicesID);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);    glBufferData(GL_ELEMENT_ARRAY_BUFFER,                 INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels,                 indicesArray, GL_STATIC_DRAW);     // delete the indices and normals arrays that are no longer needed    delete[] indicesArray;    delete[] normalsArray;        // create our simple fragment shader if we're the first system to init    if (_perlinModulateProgram != 0) {        return;    }    switchToResourcesParentIfRequired();    _perlinModulateProgram = new ProgramObject();    _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();} void VoxelSystem::updateFullVBOs() {    updateVBOSegment(0, _voxelsInReadArrays);        // consider the _readVoxelDirtyArray[] clean!    memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool));} void VoxelSystem::updatePartialVBOs() {    glBufferIndex segmentStart = 0;    bool inSegment = false;    for (glBufferIndex i = 0; i < _voxelsInReadArrays; i++) {        bool thisVoxelDirty = _readVoxelDirtyArray[i];        if (!inSegment) {            if (thisVoxelDirty) {                segmentStart = i;                inSegment = true;                _readVoxelDirtyArray[i] = false; // consider us clean!            }        } else {            if (!thisVoxelDirty) {                // If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before                // this one and so that's where the "segment" ends                updateVBOSegment(segmentStart, i - 1);                inSegment = false;            }            _readVoxelDirtyArray[i] = false; // consider us clean!        }    }        // if we got to the end of the array, and we're in an active dirty segment...    if (inSegment) {            updateVBOSegment(segmentStart, _voxelsInReadArrays - 1);        inSegment = false;    }} void VoxelSystem::updateVBOs() {    static char buffer[40] = { 0 };    if (_renderWarningsOn) {         sprintf(buffer, "updateVBOs() _readRenderFullVBO=%s", debug::valueOf(_readRenderFullVBO));    };    PerformanceWarning warn(_renderWarningsOn, buffer); // would like to include _callsToTreesToArrays    if (_voxelsDirty) {        if (_readRenderFullVBO) {            updateFullVBOs();        } else {            updatePartialVBOs();        }        _voxelsDirty = false;        _readRenderFullVBO = false;    }    _callsToTreesToArrays = 0; // clear it} void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {    int segmentLength = (segmentEnd - segmentStart) + 1;    GLintptr   segmentStartAt   = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);    GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat);    GLfloat* readVerticesFrom   = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL);    glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);    glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);    segmentStartAt          = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);    segmentSizeBytes        = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte);    GLubyte* readColorsFrom = _readColorsArray   + (segmentStart * VERTEX_POINTS_PER_VOXEL);    glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);    glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);} void VoxelSystem::render(bool texture) {    PerformanceWarning warn(_renderWarningsOn, "render()");        // get the lock so that the update thread won't change anything    pthread_mutex_lock(&_bufferWriteLock);        updateVBOs();        // tell OpenGL where to find vertex and color information    glEnableClientState(GL_VERTEX_ARRAY);    glEnableClientState(GL_NORMAL_ARRAY);    glEnableClientState(GL_COLOR_ARRAY);     glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);    glVertexPointer(3, GL_FLOAT, 0, 0);     glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID);    glNormalPointer(GL_FLOAT, 0, 0);     glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);    glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);     applyScaleAndBindProgram(texture);        // for performance, disable blending and enable backface culling    glDisable(GL_BLEND);    glEnable(GL_CULL_FACE);     // draw the number of voxels we have    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);    glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,        36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);     glEnable(GL_BLEND);    glDisable(GL_CULL_FACE);     removeScaleAndReleaseProgram(texture);        // deactivate vertex and color arrays after drawing    glDisableClientState(GL_VERTEX_ARRAY);    glDisableClientState(GL_NORMAL_ARRAY);    glDisableClientState(GL_COLOR_ARRAY);     // bind with 0 to switch back to normal operation    glBindBuffer(GL_ARRAY_BUFFER, 0);    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);        pthread_mutex_unlock(&_bufferWriteLock);} void VoxelSystem::applyScaleAndBindProgram(bool texture) {    glPushMatrix();    glScalef(_treeScale, _treeScale, _treeScale);     if (texture) {        _perlinModulateProgram->bind();        glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID());    }} void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {    // scale back down to 1 so heads aren't massive    glPopMatrix();        if (texture) {        _perlinModulateProgram->release();        glBindTexture(GL_TEXTURE_2D, 0);    }} int VoxelSystem::_nodeCount = 0; void VoxelSystem::killLocalVoxels() {    _tree->eraseAllVoxels();    _voxelsInWriteArrays = _voxelsInReadArrays = 0; // better way to do this??    //setupNewVoxelsForDrawing();}  bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {    _nodeCount++;    if (node->isColored()) {        nodeColor newColor = { 255, randomColorValue(150), randomColorValue(150), 1 };        node->setColor(newColor);    }    return true;} void VoxelSystem::randomizeVoxelColors() {    _nodeCount = 0;    _tree->recurseTreeWithOperation(randomColorOperation);    qDebug("setting randomized true color for %d nodes\n", _nodeCount);    _tree->setDirtyBit();    setupNewVoxelsForDrawing();} bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData) {    _nodeCount++;    // always false colorize    node->setFalseColor(255, randomColorValue(150), randomColorValue(150));    return true; // keep going!} void VoxelSystem::falseColorizeRandom() {    _nodeCount = 0;    _tree->recurseTreeWithOperation(falseColorizeRandomOperation);    qDebug("setting randomized false color for %d nodes\n", _nodeCount);    _tree->setDirtyBit();    setupNewVoxelsForDrawing();} bool VoxelSystem::trueColorizeOperation(VoxelNode* node, void* extraData) {    _nodeCount++;    node->setFalseColored(false);    return true;} void VoxelSystem::trueColorize() {    PerformanceWarning warn(true, "trueColorize()",true);    _nodeCount = 0;    _tree->recurseTreeWithOperation(trueColorizeOperation);    qDebug("setting true color for %d nodes\n", _nodeCount);    _tree->setDirtyBit();    setupNewVoxelsForDrawing();} // Will false colorize voxels that are not in viewbool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, void* extraData) {    const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData;    _nodeCount++;    if (node->isColored()) {        if (!node->isInView(*viewFrustum)) {            // Out of view voxels are colored RED            node->setFalseColor(255, 0, 0);        }    }    return true; // keep going!} void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) {    _nodeCount = 0;    _tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum);    qDebug("setting in view false color for %d nodes\n", _nodeCount);    _tree->setDirtyBit();    setupNewVoxelsForDrawing();} // helper classes and args for falseColorizeBySourceclass groupColor {public:    unsigned char red, green, blue;    groupColor(unsigned char red, unsigned char green, unsigned char blue) :        red(red), green(green), blue(blue) { };     groupColor() :        red(0), green(0), blue(0) { };}; class colorizeBySourceArgs {public:    std::map<uint16_t, groupColor> colors;}; // Will false colorize voxels that are not in viewbool VoxelSystem::falseColorizeBySourceOperation(VoxelNode* node, void* extraData) {    colorizeBySourceArgs* args = (colorizeBySourceArgs*)extraData;    _nodeCount++;    if (node->isColored()) {        // pick a color based on the source - we want each source to be obviously different        uint16_t nodeID = node->getSourceID();                //printf("false colorizing from source %d, color: %d, %d, %d\n", nodeID,         //        args->colors[nodeID].red, args->colors[nodeID].green,  args->colors[nodeID].blue);                        node->setFalseColor(args->colors[nodeID].red, args->colors[nodeID].green,  args->colors[nodeID].blue);    }    return true; // keep going!} void VoxelSystem::falseColorizeBySource() {    _nodeCount = 0;    colorizeBySourceArgs args;    const int NUMBER_OF_COLOR_GROUPS = 6;    const unsigned char MIN_COLOR = 128;    int voxelServerCount = 0;    groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = {         groupColor(255,   0,   0),         groupColor(  0, 255,   0),         groupColor(  0,   0, 255),        groupColor(255,   0, 255),        groupColor(  0, 255, 255),        groupColor(255, 255, 255)    };     // create a bunch of colors we'll use during colorization    NodeList* nodeList = NodeList::getInstance();    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {        if (node->getType() == NODE_TYPE_VOXEL_SERVER) {            uint16_t nodeID = node->getNodeID();            int groupColor = voxelServerCount % NUMBER_OF_COLOR_GROUPS;            args.colors[nodeID] = groupColors[groupColor];             //printf("assigning color for source %d, color: %d, %d, %d\n", nodeID,            //       args.colors[nodeID].red, args.colors[nodeID].green, args.colors[nodeID].blue);                        if (groupColors[groupColor].red > 0) {                groupColors[groupColor].red = ((groupColors[groupColor].red - MIN_COLOR)/2) + MIN_COLOR;            }            if (groupColors[groupColor].green > 0) {                groupColors[groupColor].green = ((groupColors[groupColor].green - MIN_COLOR)/2) + MIN_COLOR;            }            if (groupColors[groupColor].blue > 0) {                groupColors[groupColor].blue = ((groupColors[groupColor].blue - MIN_COLOR)/2) + MIN_COLOR;            }             voxelServerCount++;        }    }        _tree->recurseTreeWithOperation(falseColorizeBySourceOperation, &args);    qDebug("setting false color by source for %d nodes\n", _nodeCount);    _tree->setDirtyBit();    setupNewVoxelsForDrawing();} // Will false colorize voxels based on distance from viewbool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, void* extraData) {    ViewFrustum* viewFrustum = (ViewFrustum*) extraData;    if (node->isColored()) {        float distance = node->distanceToCamera(*viewFrustum);        _nodeCount++;        float distanceRatio = (_minDistance == _maxDistance) ? 1 : (distance - _minDistance) / (_maxDistance - _minDistance);         // We want to colorize this in 16 bug chunks of color        const unsigned char maxColor = 255;        const unsigned char colorBands = 16;        const unsigned char gradientOver = 128;        unsigned char colorBand = (colorBands * distanceRatio);        node->setFalseColor((colorBand * (gradientOver / colorBands)) + (maxColor - gradientOver), 0, 0);    }    return true; // keep going!} float VoxelSystem::_maxDistance = 0.0;float VoxelSystem::_minDistance = FLT_MAX; // Helper function will get the distance from view range, would be nice if you could just keep track// of this as voxels are created and/or colored... seems like some transform math could do that so// we wouldn't need to do two passes of the treebool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, void* extraData) {    ViewFrustum* viewFrustum = (ViewFrustum*) extraData;    // only do this for truly colored voxels...    if (node->isColored()) {        float distance = node->distanceToCamera(*viewFrustum);        // calculate the range of distances        if (distance > _maxDistance) {            _maxDistance = distance;        }        if (distance < _minDistance) {            _minDistance = distance;        }        _nodeCount++;    }    return true; // keep going!} void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) {    _nodeCount = 0;    _maxDistance = 0.0;    _minDistance = FLT_MAX;    _tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum);    qDebug("determining distance range for %d nodes\n", _nodeCount);    _nodeCount = 0;    _tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum);    qDebug("setting in distance false color for %d nodes\n", _nodeCount);    _tree->setDirtyBit();    setupNewVoxelsForDrawing();} // combines the removeOutOfView args into a single classclass removeOutOfViewArgs {public:    VoxelSystem*    thisVoxelSystem;    VoxelNodeBag    dontRecurseBag;    unsigned long   nodesScanned;    unsigned long   nodesRemoved;    unsigned long   nodesInside;    unsigned long   nodesIntersect;    unsigned long   nodesOutside;        removeOutOfViewArgs(VoxelSystem* voxelSystem) :        thisVoxelSystem(voxelSystem),        dontRecurseBag(),        nodesScanned(0),        nodesRemoved(0),        nodesInside(0),        nodesIntersect(0),        nodesOutside(0)    { }}; // "Remove" voxels from the tree that are not in view. We don't actually delete them,// we remove them from the tree and place them into a holding area for later deletionbool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) {    removeOutOfViewArgs* args = (removeOutOfViewArgs*)extraData;     // If our node was previously added to the don't recurse bag, then return false to    // stop the further recursion. This means that the whole node and it's children are    // known to be in view, so don't recurse them    if (args->dontRecurseBag.contains(node)) {        args->dontRecurseBag.remove(node);        return false; // stop recursion    }        VoxelSystem* thisVoxelSystem = args->thisVoxelSystem;    args->nodesScanned++;    // Need to operate on our child nodes, so we can remove them    for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {        VoxelNode* childNode = node->getChildAtIndex(i);        if (childNode) {            ViewFrustum::location inFrustum = childNode->inFrustum(*Application::getInstance()->getViewFrustum());            switch (inFrustum) {                case ViewFrustum::OUTSIDE: {                    args->nodesOutside++;                    args->nodesRemoved++;                    node->removeChildAtIndex(i);                    thisVoxelSystem->_removedVoxels.insert(childNode);                    // by removing the child, it will not get recursed!                } break;                case ViewFrustum::INSIDE: {                    // if the child node is fully INSIDE the view, then there's no need to recurse it                    // because we know all it's children will also be in the view, so we want to                     // tell the caller to NOT recurse this child                    args->nodesInside++;                    args->dontRecurseBag.insert(childNode);                } break;                case ViewFrustum::INTERSECT: {                    // if the child node INTERSECTs the view, then we don't want to remove it because                    // it is at least partially in view. But we DO want to recurse the children because                    // some of them may not be in view... nothing specifically to do, just keep iterating                    // the children                    args->nodesIntersect++;

Lines 501–1000 of 1579. Previous lines