3173 lines · 138.0 KB · C++
RawDownload
} QByteArray HeightfieldBuffer::getUnextendedHeight() const {    int srcSize = glm::sqrt(float(_height.size()));    int destSize = srcSize - 3;    QByteArray unextended(destSize * destSize, 0);    const char* src = _height.constData() + srcSize + 1;    char* dest = unextended.data();    for (int z = 0; z < destSize; z++, src += srcSize, dest += destSize) {        memcpy(dest, src, destSize);    }    return unextended;} QByteArray HeightfieldBuffer::getUnextendedColor(int x, int y) const {    int unextendedSize = _heightSize - HEIGHT_EXTENSION;    QByteArray unextended(unextendedSize * unextendedSize * DataBlock::COLOR_BYTES, 0);    char* dest = unextended.data();    const char* src = _color.constData() + (y * _colorSize + x) * unextendedSize * DataBlock::COLOR_BYTES;    for (int z = 0; z < unextendedSize; z++, dest += unextendedSize * DataBlock::COLOR_BYTES,            src += _colorSize * DataBlock::COLOR_BYTES) {        memcpy(dest, src, unextendedSize * DataBlock::COLOR_BYTES);    }    return unextended;} class HeightfieldPoint {public:    glm::vec2 textureCoord;    glm::vec3 vertex;}; const int SPLAT_COUNT = 4;const GLint SPLAT_TEXTURE_UNITS[] = { 3, 4, 5, 6 }; void HeightfieldBuffer::render(bool cursor) {    // initialize textures, etc. on first render    if (_heightTextureID == 0) {        glGenTextures(1, &_heightTextureID);        glBindTexture(GL_TEXTURE_2D, _heightTextureID);        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);        glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _heightSize, _heightSize, 0,            GL_LUMINANCE, GL_UNSIGNED_BYTE, _height.constData());                glGenTextures(1, &_colorTextureID);        glBindTexture(GL_TEXTURE_2D, _colorTextureID);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);        if (_color.isEmpty()) {            const quint8 WHITE_COLOR[] = { 255, 255, 255 };            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR);                       } else {            int colorSize = glm::sqrt(float(_color.size() / DataBlock::COLOR_BYTES));            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData());        }                if (!_material.isEmpty()) {            glGenTextures(1, &_materialTextureID);            glBindTexture(GL_TEXTURE_2D, _materialTextureID);            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);            int materialSize = glm::sqrt(float(_material.size()));            glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, materialSize, materialSize, 0,                GL_LUMINANCE, GL_UNSIGNED_BYTE, _material.constData());                        _networkTextures.resize(_materials.size());            for (int i = 0; i < _materials.size(); i++) {                const SharedObjectPointer material = _materials.at(i);                if (material) {                    _networkTextures[i] = Application::getInstance()->getTextureCache()->getTexture(                        static_cast<MaterialObject*>(material.data())->getDiffuse(), SPLAT_TEXTURE);                }            }        }    }    // create the buffer objects lazily    int innerSize = _heightSize - 2 * HeightfieldBuffer::HEIGHT_BORDER;    int vertexCount = _heightSize * _heightSize;    int rows = _heightSize - 1;    int indexCount = rows * rows * 3 * 2;    BufferPair& bufferPair = _bufferPairs[_heightSize];    if (!bufferPair.first.isCreated()) {        QVector<HeightfieldPoint> vertices(vertexCount);        HeightfieldPoint* point = vertices.data();                float vertexStep = 1.0f / (innerSize - 1);        float z = -vertexStep;        float textureStep = 1.0f / _heightSize;        float t = textureStep / 2.0f;        for (int i = 0; i < _heightSize; i++, z += vertexStep, t += textureStep) {            float x = -vertexStep;            float s = textureStep / 2.0f;            const float SKIRT_LENGTH = 0.25f;            float baseY = (i == 0 || i == _heightSize - 1) ? -SKIRT_LENGTH : 0.0f;            for (int j = 0; j < _heightSize; j++, point++, x += vertexStep, s += textureStep) {                point->vertex = glm::vec3(x, (j == 0 || j == _heightSize - 1) ? -SKIRT_LENGTH : baseY, z);                point->textureCoord = glm::vec2(s, t);            }        }                bufferPair.first.setUsagePattern(QOpenGLBuffer::StaticDraw);        bufferPair.first.create();        bufferPair.first.bind();        bufferPair.first.allocate(vertices.constData(), vertexCount * sizeof(HeightfieldPoint));                QVector<int> indices(indexCount);        int* index = indices.data();        for (int i = 0; i < rows; i++) {            int lineIndex = i * _heightSize;            int nextLineIndex = (i + 1) * _heightSize;            for (int j = 0; j < rows; j++) {                *index++ = lineIndex + j;                *index++ = nextLineIndex + j;                *index++ = nextLineIndex + j + 1;                                *index++ = nextLineIndex + j + 1;                *index++ = lineIndex + j + 1;                *index++ = lineIndex + j;            }        }                bufferPair.second = QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);        bufferPair.second.create();        bufferPair.second.bind();        bufferPair.second.allocate(indices.constData(), indexCount * sizeof(int));            } else {        bufferPair.first.bind();        bufferPair.second.bind();    }        HeightfieldPoint* point = 0;    glVertexPointer(3, GL_FLOAT, sizeof(HeightfieldPoint), &point->vertex);    glTexCoordPointer(2, GL_FLOAT, sizeof(HeightfieldPoint), &point->textureCoord);        glPushMatrix();    glTranslatef(_translation.x, _translation.y, _translation.z);    glScalef(_scale, _scale, _scale);        glBindTexture(GL_TEXTURE_2D, _heightTextureID);        if (cursor) {        glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);        } else if (!_materials.isEmpty()) {        DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(            DefaultMetavoxelRendererImplementation::getBaseHeightScaleLocation(), 1.0f / _heightSize);        DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(            DefaultMetavoxelRendererImplementation::getBaseColorScaleLocation(), (float)_heightSize / innerSize);        glActiveTexture(GL_TEXTURE1);        glBindTexture(GL_TEXTURE_2D, _colorTextureID);                glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);                Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);                glDepthFunc(GL_LEQUAL);        glDepthMask(false);        glEnable(GL_BLEND);        glDisable(GL_ALPHA_TEST);        glEnable(GL_POLYGON_OFFSET_FILL);        glPolygonOffset(-1.0f, -1.0f);                DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().bind();        const DefaultMetavoxelRendererImplementation::SplatLocations& locations =            DefaultMetavoxelRendererImplementation::getSplatHeightfieldLocations();        DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(            locations.heightScale, 1.0f / _heightSize);        DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(            locations.textureScale, (float)_heightSize / innerSize);        DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(            locations.splatTextureOffset, _translation.x / _scale, _translation.z / _scale);                    glBindTexture(GL_TEXTURE_2D, _materialTextureID);            for (int i = 0; i < _materials.size(); i += SPLAT_COUNT) {            QVector4D scalesS, scalesT;                        for (int j = 0; j < SPLAT_COUNT; j++) {                glActiveTexture(GL_TEXTURE0 + SPLAT_TEXTURE_UNITS[j]);                int index = i + j;                if (index < _networkTextures.size()) {                    const NetworkTexturePointer& texture = _networkTextures.at(index);                    if (texture) {                        MaterialObject* material = static_cast<MaterialObject*>(_materials.at(index).data());                        scalesS[j] = _scale / material->getScaleS();                        scalesT[j] = _scale / material->getScaleT();                        glBindTexture(GL_TEXTURE_2D, texture->getID());                        } else {                        glBindTexture(GL_TEXTURE_2D, 0);                    }                } else {                    glBindTexture(GL_TEXTURE_2D, 0);                }            }            const float QUARTER_STEP = 0.25f * EIGHT_BIT_MAXIMUM_RECIPROCAL;            DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(                locations.splatTextureScalesS, scalesS);            DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(                locations.splatTextureScalesT, scalesT);            DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(                locations.textureValueMinima,                (i + 1) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP, (i + 2) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP,                (i + 3) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP, (i + 4) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP);            DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().setUniformValue(                locations.textureValueMaxima,                (i + 1) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP, (i + 2) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP,                (i + 3) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP, (i + 4) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP);            glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);        }            for (int i = 0; i < SPLAT_COUNT; i++) {            glActiveTexture(GL_TEXTURE0 + SPLAT_TEXTURE_UNITS[i]);            glBindTexture(GL_TEXTURE_2D, 0);        }            glActiveTexture(GL_TEXTURE1);        glBindTexture(GL_TEXTURE_2D, 0);                glActiveTexture(GL_TEXTURE0);                glDisable(GL_POLYGON_OFFSET_FILL);        glEnable(GL_ALPHA_TEST);        glDisable(GL_BLEND);        glDepthMask(true);        glDepthFunc(GL_LESS);                Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);                DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().bind();            } else {        DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(            DefaultMetavoxelRendererImplementation::getBaseHeightScaleLocation(), 1.0f / _heightSize);        DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue(            DefaultMetavoxelRendererImplementation::getBaseColorScaleLocation(), (float)_heightSize / innerSize);        glActiveTexture(GL_TEXTURE1);        glBindTexture(GL_TEXTURE_2D, _colorTextureID);                glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);                glBindTexture(GL_TEXTURE_2D, 0);        glActiveTexture(GL_TEXTURE0);     }        glBindTexture(GL_TEXTURE_2D, 0);        glPopMatrix();        bufferPair.first.release();    bufferPair.second.release();} QHash<int, HeightfieldBuffer::BufferPair> HeightfieldBuffer::_bufferPairs; void HeightfieldPreview::render(const glm::vec3& translation, float scale) const {    Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);        glDisable(GL_BLEND);    glEnable(GL_CULL_FACE);    glEnable(GL_ALPHA_TEST);    glAlphaFunc(GL_EQUAL, 0.0f);        glColor4f(1.0f, 1.0f, 1.0f, 1.0f);        glEnableClientState(GL_VERTEX_ARRAY);    glEnableClientState(GL_TEXTURE_COORD_ARRAY);        DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().bind();        glPushMatrix();    glTranslatef(translation.x, translation.y, translation.z);    glScalef(scale, scale, scale);        foreach (const BufferDataPointer& buffer, _buffers) {        buffer->render();    }        glPopMatrix();        DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().release();        glDisableClientState(GL_TEXTURE_COORD_ARRAY);    glDisableClientState(GL_VERTEX_ARRAY);        glDisable(GL_ALPHA_TEST);    glDisable(GL_CULL_FACE);    glEnable(GL_BLEND);        Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);} void VoxelPoint::setNormal(const glm::vec3& normal) {    this->normal[0] = (char)(normal.x * 127.0f);    this->normal[1] = (char)(normal.y * 127.0f);    this->normal[2] = (char)(normal.z * 127.0f);} VoxelBuffer::VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>& indices, const QVector<glm::vec3>& hermite,        const QMultiHash<QRgb, int>& quadIndices, int size, const QVector<SharedObjectPointer>& materials) :    _vertices(vertices),    _indices(indices),    _hermite(hermite),    _quadIndices(quadIndices),    _size(size),    _vertexCount(vertices.size()),    _indexCount(indices.size()),    _hermiteCount(hermite.size()),    _indexBuffer(QOpenGLBuffer::IndexBuffer),    _materials(materials) {} static bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction,        const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance) {    glm::vec3 firstSide = v0 - v1;    glm::vec3 secondSide = v2 - v1;    glm::vec3 normal = glm::cross(secondSide, firstSide);    float dividend = glm::dot(normal, v1) - glm::dot(origin, normal);    if (dividend > 0.0f) {        return false; // origin below plane    }    float divisor = glm::dot(normal, direction);    if (divisor > -EPSILON) {        return false;    }    float t = dividend / divisor;    glm::vec3 point = origin + direction * t;    if (glm::dot(normal, glm::cross(point - v1, firstSide)) > 0.0f &&            glm::dot(normal, glm::cross(secondSide, point - v1)) > 0.0f &&            glm::dot(normal, glm::cross(point - v0, v2 - v0)) > 0.0f) {        distance = t;        return true;    }    return false;} bool VoxelBuffer::findFirstRayIntersection(const glm::vec3& entry, const glm::vec3& origin,        const glm::vec3& direction, float& distance) const {    float highest = _size - 1.0f;    glm::vec3 position = entry * highest;    glm::vec3 floors = glm::floor(position);    int max = _size - 2;    int x = qMin((int)floors.x, max), y = qMin((int)floors.y, max), z = qMin((int)floors.z, max);    forever {        for (QMultiHash<QRgb, int>::const_iterator it = _quadIndices.constFind(qRgb(x + 1, y + 1, z + 1));                it != _quadIndices.constEnd(); it++) {            const int* indices = _indices.constData() + *it;            if (findRayTriangleIntersection(origin, direction, _vertices.at(indices[0]).vertex,                    _vertices.at(indices[1]).vertex, _vertices.at(indices[2]).vertex, distance) ||                findRayTriangleIntersection(origin, direction, _vertices.at(indices[0]).vertex,                    _vertices.at(indices[2]).vertex, _vertices.at(indices[3]).vertex, distance)) {                return true;            }        }        float xDistance = FLT_MAX, yDistance = FLT_MAX, zDistance = FLT_MAX;        if (direction.x > 0.0f) {            xDistance = (x + 1.0f - position.x) / direction.x;        } else if (direction.x < 0.0f) {            xDistance = (x - position.x) / direction.x;        }        if (direction.y > 0.0f) {            yDistance = (y + 1.0f - position.y) / direction.y;        } else if (direction.y < 0.0f) {            yDistance = (y - position.y) / direction.y;        }        if (direction.z > 0.0f) {            zDistance = (z + 1.0f - position.z) / direction.z;        } else if (direction.z < 0.0f) {            zDistance = (z - position.z) / direction.z;        }        float minimumDistance = qMin(xDistance, qMin(yDistance, zDistance));        if (minimumDistance == xDistance) {            if (direction.x > 0.0f) {                if (x++ == max) {                    return false;                }            } else if (x-- == 0) {                return false;            }        }        if (minimumDistance == yDistance) {            if (direction.y > 0.0f) {                if (y++ == max) {                    return false;                }            } else if (y-- == 0) {                return false;            }        }        if (minimumDistance == zDistance) {            if (direction.z > 0.0f) {                if (z++ == max) {                    return false;                }            } else if (z-- == 0) {                return false;            }        }        position += direction * minimumDistance;    }    return false;} void VoxelBuffer::render(bool cursor) {    if (!_vertexBuffer.isCreated()) {        _vertexBuffer.create();        _vertexBuffer.bind();        _vertexBuffer.allocate(_vertices.constData(), _vertices.size() * sizeof(VoxelPoint));                _indexBuffer.create();        _indexBuffer.bind();        _indexBuffer.allocate(_indices.constData(), _indices.size() * sizeof(int));                if (!_materials.isEmpty()) {            _networkTextures.resize(_materials.size());            for (int i = 0; i < _materials.size(); i++) {                const SharedObjectPointer material = _materials.at(i);                if (material) {                    _networkTextures[i] = Application::getInstance()->getTextureCache()->getTexture(                        static_cast<MaterialObject*>(material.data())->getDiffuse(), SPLAT_TEXTURE);                }            }        }    } else {        _vertexBuffer.bind();        _indexBuffer.bind();    }        VoxelPoint* point = 0;    glVertexPointer(3, GL_FLOAT, sizeof(VoxelPoint), &point->vertex);    glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelPoint), &point->color);    glNormalPointer(GL_BYTE, sizeof(VoxelPoint), &point->normal);        glDrawRangeElements(GL_QUADS, 0, _vertexCount - 1, _indexCount, GL_UNSIGNED_INT, 0);        if (!(_materials.isEmpty() || cursor)) {        Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);                glDepthFunc(GL_LEQUAL);        glDepthMask(false);        glEnable(GL_BLEND);        glDisable(GL_ALPHA_TEST);        glEnable(GL_POLYGON_OFFSET_FILL);        glPolygonOffset(-1.0f, -1.0f);                DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().bind();        const DefaultMetavoxelRendererImplementation::SplatLocations& locations =            DefaultMetavoxelRendererImplementation::getSplatVoxelLocations();                DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().setAttributeBuffer(locations.materials,            GL_UNSIGNED_BYTE, (qint64)&point->materials, SPLAT_COUNT, sizeof(VoxelPoint));        DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().enableAttributeArray(locations.materials);                DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().setAttributeBuffer(locations.materialWeights,            GL_UNSIGNED_BYTE, (qint64)&point->materialWeights, SPLAT_COUNT, sizeof(VoxelPoint));        DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().enableAttributeArray(locations.materialWeights);                for (int i = 0; i < _materials.size(); i += SPLAT_COUNT) {            QVector4D scalesS, scalesT;                        for (int j = 0; j < SPLAT_COUNT; j++) {                glActiveTexture(GL_TEXTURE0 + SPLAT_TEXTURE_UNITS[j]);                int index = i + j;                if (index < _networkTextures.size()) {                    const NetworkTexturePointer& texture = _networkTextures.at(index);                    if (texture) {                        MaterialObject* material = static_cast<MaterialObject*>(_materials.at(index).data());                        scalesS[j] = 1.0f / material->getScaleS();                        scalesT[j] = 1.0f / material->getScaleT();                        glBindTexture(GL_TEXTURE_2D, texture->getID());                        } else {                        glBindTexture(GL_TEXTURE_2D, 0);                    }                } else {                    glBindTexture(GL_TEXTURE_2D, 0);                }            }            const float QUARTER_STEP = 0.25f * EIGHT_BIT_MAXIMUM_RECIPROCAL;            DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().setUniformValue(                locations.splatTextureScalesS, scalesS);            DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().setUniformValue(                locations.splatTextureScalesT, scalesT);            DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().setUniformValue(                locations.textureValueMinima,                (i + 1) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP, (i + 2) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP,                (i + 3) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP, (i + 4) * EIGHT_BIT_MAXIMUM_RECIPROCAL - QUARTER_STEP);            DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().setUniformValue(                locations.textureValueMaxima,                (i + 1) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP, (i + 2) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP,                (i + 3) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP, (i + 4) * EIGHT_BIT_MAXIMUM_RECIPROCAL + QUARTER_STEP);            glDrawRangeElements(GL_QUADS, 0, _vertexCount - 1, _indexCount, GL_UNSIGNED_INT, 0);        }

Lines 1001–1500 of 3173. Previous lines