} 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 Load more
} 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); }