for (int i = 0; i < SPLAT_COUNT; i++) { glActiveTexture(GL_TEXTURE0 + SPLAT_TEXTURE_UNITS[i]); 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::getSplatVoxelProgram().disableAttributeArray(locations.materials); DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().disableAttributeArray(locations.materialWeights); DefaultMetavoxelRendererImplementation::getBaseVoxelProgram().bind(); } _vertexBuffer.release(); _indexBuffer.release(); if (_hermiteCount > 0 && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHermiteData) && !cursor) { if (!_hermiteBuffer.isCreated()) { _hermiteBuffer.create(); _hermiteBuffer.bind(); _hermiteBuffer.allocate(_hermite.constData(), _hermite.size() * sizeof(glm::vec3)); _hermite.clear(); } else { _hermiteBuffer.bind(); } glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 0, 0); Application::getInstance()->getDeferredLightingEffect()->getSimpleProgram().bind(); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glNormal3f(0.0f, 1.0f, 0.0f); glLineWidth(1.0f); glDrawArrays(GL_LINES, 0, _hermiteCount); DefaultMetavoxelRendererImplementation::getBaseVoxelProgram().bind(); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); _hermiteBuffer.release(); }} BufferDataAttribute::BufferDataAttribute(const QString& name) : InlineAttribute<BufferDataPointer>(name) {} bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const { *(BufferDataPointer*)&parent = _defaultValue; for (int i = 0; i < MERGE_COUNT; i++) { if (decodeInline<BufferDataPointer>(children[i])) { return false; } } return true;} AttributeValue BufferDataAttribute::inherit(const AttributeValue& parentValue) const { return AttributeValue(parentValue.getAttribute());} void DefaultMetavoxelRendererImplementation::init() { if (!_pointProgram.isLinked()) { _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); _pointProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_voxel_base.frag"); _pointProgram.link(); _pointProgram.bind(); _pointScaleLocation = _pointProgram.uniformLocation("pointScale"); _pointProgram.release(); _baseHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_heightfield_base.vert"); _baseHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_heightfield_base.frag"); _baseHeightfieldProgram.link(); _baseHeightfieldProgram.bind(); _baseHeightfieldProgram.setUniformValue("heightMap", 0); _baseHeightfieldProgram.setUniformValue("diffuseMap", 1); _baseHeightScaleLocation = _baseHeightfieldProgram.uniformLocation("heightScale"); _baseColorScaleLocation = _baseHeightfieldProgram.uniformLocation("colorScale"); _baseHeightfieldProgram.release(); loadSplatProgram("heightfield", _splatHeightfieldProgram, _splatHeightfieldLocations); _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_heightfield_cursor.vert"); _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_cursor.frag"); _heightfieldCursorProgram.link(); _heightfieldCursorProgram.bind(); _heightfieldCursorProgram.setUniformValue("heightMap", 0); _heightfieldCursorProgram.release(); _baseVoxelProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_voxel_base.vert"); _baseVoxelProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_voxel_base.frag"); _baseVoxelProgram.link(); loadSplatProgram("voxel", _splatVoxelProgram, _splatVoxelLocations); _voxelCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_voxel_cursor.vert"); _voxelCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_cursor.frag"); _voxelCursorProgram.link(); }} DefaultMetavoxelRendererImplementation::DefaultMetavoxelRendererImplementation() {} class PointAugmentVisitor : public MetavoxelVisitor {public: PointAugmentVisitor(const MetavoxelLOD& lod); virtual void prepare(MetavoxelData* data); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: BufferPointVector _points; float _pointLeafSize;}; PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() << AttributeRegistry::getInstance()->getNormalAttribute(), QVector<AttributePointer>() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) {} const int ALPHA_RENDER_THRESHOLD = 0; void PointAugmentVisitor::prepare(MetavoxelData* data) { MetavoxelVisitor::prepare(data); const float MAX_POINT_LEAF_SIZE = 64.0f; _pointLeafSize = qMin(data->getSize(), MAX_POINT_LEAF_SIZE);} int PointAugmentVisitor::visit(MetavoxelInfo& info) { if (!info.isLeaf) { return (info.size > _pointLeafSize) ? DEFAULT_ORDER : (DEFAULT_ORDER | ALL_NODES_REST); } QRgb color = info.inputValues.at(0).getInlineValue<QRgb>(); quint8 alpha = qAlpha(color); if (alpha > ALPHA_RENDER_THRESHOLD) { QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>(); BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) }, { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; _points.append(point); } if (info.size >= _pointLeafSize) { PointBuffer* buffer = NULL; if (!_points.isEmpty()) { BufferPointVector swapPoints; _points.swap(swapPoints); buffer = new PointBuffer(swapPoints); } BufferDataPointer pointer(buffer); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); } return STOP_RECURSION;} bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { if (info.size != _pointLeafSize) { return false; } PointBuffer* buffer = NULL; if (!_points.isEmpty()) { BufferPointVector swapPoints; _points.swap(swapPoints); buffer = new PointBuffer(swapPoints); } BufferDataPointer pointer(buffer); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); return true;} class HeightfieldFetchVisitor : public MetavoxelVisitor {public: HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections); void init(HeightfieldBuffer* buffer); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: const QVector<Box>& _intersections; HeightfieldBuffer* _buffer; QVector<int> _depthFlags;}; enum DepthFlags { HEIGHT_FLAG = 0x01, COLOR_FLAG = 0x02, MATERIAL_FLAG = 0x04 }; HeightfieldFetchVisitor::HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute() << AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute(), QVector<AttributePointer>(), lod), _intersections(intersections) {} void HeightfieldFetchVisitor::init(HeightfieldBuffer* buffer) { _buffer = buffer;} int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) { if (!info.getBounds().intersects(_buffer->getHeightBounds())) { return STOP_RECURSION; } if (_depthFlags.size() > _depth) { _depthFlags[_depth] = 0; } else { _depthFlags.append(0); } if (!info.isLeaf) { return DEFAULT_ORDER; } postVisit(info); return STOP_RECURSION;} bool HeightfieldFetchVisitor::postVisit(MetavoxelInfo& info) { HeightfieldHeightDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>(); int flags = _depthFlags.at(_depth); if (height) { // to handle borders correctly, make sure we only sample nodes with resolution <= ours int heightSize = glm::sqrt((float)height->getContents().size()); float heightIncrement = info.size / heightSize; if (heightIncrement < _buffer->getHeightIncrement() || (flags & HEIGHT_FLAG)) { height.reset(); } else { flags |= HEIGHT_FLAG; } } HeightfieldColorDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>(); if (color) { int colorSize = glm::sqrt((float)color->getContents().size() / DataBlock::COLOR_BYTES); float colorIncrement = info.size / colorSize; if (colorIncrement < _buffer->getColorIncrement() || (flags & COLOR_FLAG)) { color.reset(); } else { flags |= COLOR_FLAG; } } HeightfieldMaterialDataPointer material = info.inputValues.at(2).getInlineValue<HeightfieldMaterialDataPointer>(); if (material) { int materialSize = glm::sqrt((float)material->getContents().size()); float materialIncrement = info.size / materialSize; if (materialIncrement < _buffer->getMaterialIncrement() || (flags & MATERIAL_FLAG)) { material.reset(); } else { flags |= MATERIAL_FLAG; } } if (_depth > 0) { _depthFlags[_depth - 1] |= flags; } if (!(height || color || material)) { return false; } Box bounds = info.getBounds(); foreach (const Box& intersection, _intersections) { Box overlap = intersection.getIntersection(bounds); if (overlap.isEmpty()) { continue; } if (height) { float heightIncrement = _buffer->getHeightIncrement(); const Box& heightBounds = _buffer->getHeightBounds(); int destX = (overlap.minimum.x - heightBounds.minimum.x) / heightIncrement; int destY = (overlap.minimum.z - heightBounds.minimum.z) / heightIncrement; int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / heightIncrement); int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / heightIncrement); int heightSize = _buffer->getHeightSize(); char* dest = _buffer->getHeight().data() + destY * heightSize + destX; const QByteArray& srcHeight = height->getContents(); int srcSize = glm::sqrt((float)srcHeight.size()); float srcIncrement = info.size / srcSize; if (info.size == _buffer->getScale() && srcSize == (heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) { // easy case: same resolution int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; const char* src = srcHeight.constData() + srcY * srcSize + srcX; for (int y = 0; y < destHeight; y++, src += srcSize, dest += heightSize) { memcpy(dest, src, destWidth); } } else { // more difficult: different resolutions float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; float srcAdvance = heightIncrement / srcIncrement; int shift = 0; float size = _buffer->getScale(); while (size < info.size) { shift++; size *= 2.0f; } int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale(); for (int y = 0; y < destHeight; y++, dest += heightSize, srcY += srcAdvance) { const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize; float lineSrcX = srcX; for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) { *lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM); } } } } if (color) { const Box& colorBounds = _buffer->getColorBounds(); overlap = colorBounds.getIntersection(overlap); float colorIncrement = _buffer->getColorIncrement(); int destX = (overlap.minimum.x - colorBounds.minimum.x) / colorIncrement; int destY = (overlap.minimum.z - colorBounds.minimum.z) / colorIncrement; int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / colorIncrement); int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / colorIncrement); int colorSize = _buffer->getColorSize(); char* dest = _buffer->getColor().data() + (destY * colorSize + destX) * DataBlock::COLOR_BYTES; int destStride = colorSize * DataBlock::COLOR_BYTES; int destBytes = destWidth * DataBlock::COLOR_BYTES; const QByteArray& srcColor = color->getContents(); int srcSize = glm::sqrt(float(srcColor.size() / DataBlock::COLOR_BYTES)); int srcStride = srcSize * DataBlock::COLOR_BYTES; float srcIncrement = info.size / srcSize; if (srcIncrement == colorIncrement) { // easy case: same resolution int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; const char* src = srcColor.constData() + (srcY * srcSize + srcX) * DataBlock::COLOR_BYTES; for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) { memcpy(dest, src, destBytes); } } else { // more difficult: different resolutions float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; float srcAdvance = colorIncrement / srcIncrement; for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcAdvance) { const char* src = srcColor.constData() + (int)srcY * srcStride; float lineSrcX = srcX; for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += DataBlock::COLOR_BYTES, lineSrcX += srcAdvance) { const char* lineSrc = src + (int)lineSrcX * DataBlock::COLOR_BYTES; lineDest[0] = lineSrc[0]; lineDest[1] = lineSrc[1]; lineDest[2] = lineSrc[2]; } } } } if (material) { const Box& materialBounds = _buffer->getMaterialBounds(); overlap = materialBounds.getIntersection(overlap); float materialIncrement = _buffer->getMaterialIncrement(); int destX = (overlap.minimum.x - materialBounds.minimum.x) / materialIncrement; int destY = (overlap.minimum.z - materialBounds.minimum.z) / materialIncrement; int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / materialIncrement); int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / materialIncrement); int materialSize = _buffer->getMaterialSize(); char* dest = _buffer->getMaterial().data() + destY * materialSize + destX; const QByteArray& srcMaterial = material->getContents(); const QVector<SharedObjectPointer> srcMaterials = material->getMaterials(); int srcSize = glm::sqrt((float)srcMaterial.size()); float srcIncrement = info.size / srcSize; QHash<int, int> materialMappings; if (srcIncrement == materialIncrement) { // easy case: same resolution int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; const uchar* src = (const uchar*)srcMaterial.constData() + srcY * srcSize + srcX; for (int y = 0; y < destHeight; y++, src += srcSize, dest += materialSize) { const uchar* lineSrc = src; for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrc++) { int value = *lineSrc; if (value != 0) { int& mapping = materialMappings[value]; if (mapping == 0) { mapping = getMaterialIndex(material->getMaterials().at(value - 1), _buffer->getMaterials(), _buffer->getMaterial()); } value = mapping; } *lineDest = value; } } } else { // more difficult: different resolutions float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; float srcAdvance = materialIncrement / srcIncrement; for (int y = 0; y < destHeight; y++, dest += materialSize, srcY += srcAdvance) { const uchar* src = (const uchar*)srcMaterial.constData() + (int)srcY * srcSize; float lineSrcX = srcX; for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) { int value = src[(int)lineSrcX]; if (value != 0) { int& mapping = materialMappings[value]; if (mapping == 0) { mapping = getMaterialIndex(material->getMaterials().at(value - 1), _buffer->getMaterials(), _buffer->getMaterial()); } value = mapping; } *lineDest = value; } } } clearUnusedMaterials(_buffer->getMaterials(), _buffer->getMaterial()); } } return false;} class HeightfieldRegionVisitor : public MetavoxelVisitor {public: QVector<Box> regions; Box regionBounds; HeightfieldRegionVisitor(const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: void addRegion(const Box& unextended, const Box& extended); class DepthInfo { public: float minimumColorIncrement; float minimumMaterialIncrement; DepthInfo() : minimumColorIncrement(FLT_MAX), minimumMaterialIncrement(FLT_MAX) { } }; QVector<DepthInfo> _depthInfo; QVector<Box> _intersections; HeightfieldFetchVisitor _fetchVisitor;}; HeightfieldRegionVisitor::HeightfieldRegionVisitor(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute() << AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute() << Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() << Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod), regionBounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)), _fetchVisitor(lod, _intersections) {} int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) { DepthInfo depthInfo; HeightfieldColorDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>(); if (color) { int colorSize = glm::sqrt((float)color->getContents().size() / DataBlock::COLOR_BYTES); depthInfo.minimumColorIncrement = info.size / colorSize; } HeightfieldMaterialDataPointer material = info.inputValues.at(2).getInlineValue<HeightfieldMaterialDataPointer>(); if (material) { int materialSize = glm::sqrt((float)material->getContents().size()); depthInfo.minimumMaterialIncrement = info.size / materialSize;Lines 1501–2000 of 3173. Previous lines Load more
for (int i = 0; i < SPLAT_COUNT; i++) { glActiveTexture(GL_TEXTURE0 + SPLAT_TEXTURE_UNITS[i]); 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::getSplatVoxelProgram().disableAttributeArray(locations.materials); DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().disableAttributeArray(locations.materialWeights); DefaultMetavoxelRendererImplementation::getBaseVoxelProgram().bind(); } _vertexBuffer.release(); _indexBuffer.release(); if (_hermiteCount > 0 && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHermiteData) && !cursor) { if (!_hermiteBuffer.isCreated()) { _hermiteBuffer.create(); _hermiteBuffer.bind(); _hermiteBuffer.allocate(_hermite.constData(), _hermite.size() * sizeof(glm::vec3)); _hermite.clear(); } else { _hermiteBuffer.bind(); } glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 0, 0); Application::getInstance()->getDeferredLightingEffect()->getSimpleProgram().bind(); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glNormal3f(0.0f, 1.0f, 0.0f); glLineWidth(1.0f); glDrawArrays(GL_LINES, 0, _hermiteCount); DefaultMetavoxelRendererImplementation::getBaseVoxelProgram().bind(); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); _hermiteBuffer.release(); } } BufferDataAttribute::BufferDataAttribute(const QString& name) : InlineAttribute<BufferDataPointer>(name) { } bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const { *(BufferDataPointer*)&parent = _defaultValue; for (int i = 0; i < MERGE_COUNT; i++) { if (decodeInline<BufferDataPointer>(children[i])) { return false; } } return true; } AttributeValue BufferDataAttribute::inherit(const AttributeValue& parentValue) const { return AttributeValue(parentValue.getAttribute()); } void DefaultMetavoxelRendererImplementation::init() { if (!_pointProgram.isLinked()) { _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); _pointProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_voxel_base.frag"); _pointProgram.link(); _pointProgram.bind(); _pointScaleLocation = _pointProgram.uniformLocation("pointScale"); _pointProgram.release(); _baseHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_heightfield_base.vert"); _baseHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_heightfield_base.frag"); _baseHeightfieldProgram.link(); _baseHeightfieldProgram.bind(); _baseHeightfieldProgram.setUniformValue("heightMap", 0); _baseHeightfieldProgram.setUniformValue("diffuseMap", 1); _baseHeightScaleLocation = _baseHeightfieldProgram.uniformLocation("heightScale"); _baseColorScaleLocation = _baseHeightfieldProgram.uniformLocation("colorScale"); _baseHeightfieldProgram.release(); loadSplatProgram("heightfield", _splatHeightfieldProgram, _splatHeightfieldLocations); _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_heightfield_cursor.vert"); _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_cursor.frag"); _heightfieldCursorProgram.link(); _heightfieldCursorProgram.bind(); _heightfieldCursorProgram.setUniformValue("heightMap", 0); _heightfieldCursorProgram.release(); _baseVoxelProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_voxel_base.vert"); _baseVoxelProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_voxel_base.frag"); _baseVoxelProgram.link(); loadSplatProgram("voxel", _splatVoxelProgram, _splatVoxelLocations); _voxelCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_voxel_cursor.vert"); _voxelCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/metavoxel_cursor.frag"); _voxelCursorProgram.link(); } } DefaultMetavoxelRendererImplementation::DefaultMetavoxelRendererImplementation() { } class PointAugmentVisitor : public MetavoxelVisitor { public: PointAugmentVisitor(const MetavoxelLOD& lod); virtual void prepare(MetavoxelData* data); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: BufferPointVector _points; float _pointLeafSize; }; PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() << AttributeRegistry::getInstance()->getNormalAttribute(), QVector<AttributePointer>() << Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) { } const int ALPHA_RENDER_THRESHOLD = 0; void PointAugmentVisitor::prepare(MetavoxelData* data) { MetavoxelVisitor::prepare(data); const float MAX_POINT_LEAF_SIZE = 64.0f; _pointLeafSize = qMin(data->getSize(), MAX_POINT_LEAF_SIZE); } int PointAugmentVisitor::visit(MetavoxelInfo& info) { if (!info.isLeaf) { return (info.size > _pointLeafSize) ? DEFAULT_ORDER : (DEFAULT_ORDER | ALL_NODES_REST); } QRgb color = info.inputValues.at(0).getInlineValue<QRgb>(); quint8 alpha = qAlpha(color); if (alpha > ALPHA_RENDER_THRESHOLD) { QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>(); BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) }, { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; _points.append(point); } if (info.size >= _pointLeafSize) { PointBuffer* buffer = NULL; if (!_points.isEmpty()) { BufferPointVector swapPoints; _points.swap(swapPoints); buffer = new PointBuffer(swapPoints); } BufferDataPointer pointer(buffer); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); } return STOP_RECURSION; } bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { if (info.size != _pointLeafSize) { return false; } PointBuffer* buffer = NULL; if (!_points.isEmpty()) { BufferPointVector swapPoints; _points.swap(swapPoints); buffer = new PointBuffer(swapPoints); } BufferDataPointer pointer(buffer); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); return true; } class HeightfieldFetchVisitor : public MetavoxelVisitor { public: HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections); void init(HeightfieldBuffer* buffer); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: const QVector<Box>& _intersections; HeightfieldBuffer* _buffer; QVector<int> _depthFlags; }; enum DepthFlags { HEIGHT_FLAG = 0x01, COLOR_FLAG = 0x02, MATERIAL_FLAG = 0x04 }; HeightfieldFetchVisitor::HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute() << AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute(), QVector<AttributePointer>(), lod), _intersections(intersections) { } void HeightfieldFetchVisitor::init(HeightfieldBuffer* buffer) { _buffer = buffer; } int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) { if (!info.getBounds().intersects(_buffer->getHeightBounds())) { return STOP_RECURSION; } if (_depthFlags.size() > _depth) { _depthFlags[_depth] = 0; } else { _depthFlags.append(0); } if (!info.isLeaf) { return DEFAULT_ORDER; } postVisit(info); return STOP_RECURSION; } bool HeightfieldFetchVisitor::postVisit(MetavoxelInfo& info) { HeightfieldHeightDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>(); int flags = _depthFlags.at(_depth); if (height) { // to handle borders correctly, make sure we only sample nodes with resolution <= ours int heightSize = glm::sqrt((float)height->getContents().size()); float heightIncrement = info.size / heightSize; if (heightIncrement < _buffer->getHeightIncrement() || (flags & HEIGHT_FLAG)) { height.reset(); } else { flags |= HEIGHT_FLAG; } } HeightfieldColorDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>(); if (color) { int colorSize = glm::sqrt((float)color->getContents().size() / DataBlock::COLOR_BYTES); float colorIncrement = info.size / colorSize; if (colorIncrement < _buffer->getColorIncrement() || (flags & COLOR_FLAG)) { color.reset(); } else { flags |= COLOR_FLAG; } } HeightfieldMaterialDataPointer material = info.inputValues.at(2).getInlineValue<HeightfieldMaterialDataPointer>(); if (material) { int materialSize = glm::sqrt((float)material->getContents().size()); float materialIncrement = info.size / materialSize; if (materialIncrement < _buffer->getMaterialIncrement() || (flags & MATERIAL_FLAG)) { material.reset(); } else { flags |= MATERIAL_FLAG; } } if (_depth > 0) { _depthFlags[_depth - 1] |= flags; } if (!(height || color || material)) { return false; } Box bounds = info.getBounds(); foreach (const Box& intersection, _intersections) { Box overlap = intersection.getIntersection(bounds); if (overlap.isEmpty()) { continue; } if (height) { float heightIncrement = _buffer->getHeightIncrement(); const Box& heightBounds = _buffer->getHeightBounds(); int destX = (overlap.minimum.x - heightBounds.minimum.x) / heightIncrement; int destY = (overlap.minimum.z - heightBounds.minimum.z) / heightIncrement; int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / heightIncrement); int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / heightIncrement); int heightSize = _buffer->getHeightSize(); char* dest = _buffer->getHeight().data() + destY * heightSize + destX; const QByteArray& srcHeight = height->getContents(); int srcSize = glm::sqrt((float)srcHeight.size()); float srcIncrement = info.size / srcSize; if (info.size == _buffer->getScale() && srcSize == (heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) { // easy case: same resolution int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; const char* src = srcHeight.constData() + srcY * srcSize + srcX; for (int y = 0; y < destHeight; y++, src += srcSize, dest += heightSize) { memcpy(dest, src, destWidth); } } else { // more difficult: different resolutions float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; float srcAdvance = heightIncrement / srcIncrement; int shift = 0; float size = _buffer->getScale(); while (size < info.size) { shift++; size *= 2.0f; } int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale(); for (int y = 0; y < destHeight; y++, dest += heightSize, srcY += srcAdvance) { const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize; float lineSrcX = srcX; for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) { *lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM); } } } } if (color) { const Box& colorBounds = _buffer->getColorBounds(); overlap = colorBounds.getIntersection(overlap); float colorIncrement = _buffer->getColorIncrement(); int destX = (overlap.minimum.x - colorBounds.minimum.x) / colorIncrement; int destY = (overlap.minimum.z - colorBounds.minimum.z) / colorIncrement; int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / colorIncrement); int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / colorIncrement); int colorSize = _buffer->getColorSize(); char* dest = _buffer->getColor().data() + (destY * colorSize + destX) * DataBlock::COLOR_BYTES; int destStride = colorSize * DataBlock::COLOR_BYTES; int destBytes = destWidth * DataBlock::COLOR_BYTES; const QByteArray& srcColor = color->getContents(); int srcSize = glm::sqrt(float(srcColor.size() / DataBlock::COLOR_BYTES)); int srcStride = srcSize * DataBlock::COLOR_BYTES; float srcIncrement = info.size / srcSize; if (srcIncrement == colorIncrement) { // easy case: same resolution int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; const char* src = srcColor.constData() + (srcY * srcSize + srcX) * DataBlock::COLOR_BYTES; for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) { memcpy(dest, src, destBytes); } } else { // more difficult: different resolutions float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; float srcAdvance = colorIncrement / srcIncrement; for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcAdvance) { const char* src = srcColor.constData() + (int)srcY * srcStride; float lineSrcX = srcX; for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += DataBlock::COLOR_BYTES, lineSrcX += srcAdvance) { const char* lineSrc = src + (int)lineSrcX * DataBlock::COLOR_BYTES; lineDest[0] = lineSrc[0]; lineDest[1] = lineSrc[1]; lineDest[2] = lineSrc[2]; } } } } if (material) { const Box& materialBounds = _buffer->getMaterialBounds(); overlap = materialBounds.getIntersection(overlap); float materialIncrement = _buffer->getMaterialIncrement(); int destX = (overlap.minimum.x - materialBounds.minimum.x) / materialIncrement; int destY = (overlap.minimum.z - materialBounds.minimum.z) / materialIncrement; int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / materialIncrement); int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / materialIncrement); int materialSize = _buffer->getMaterialSize(); char* dest = _buffer->getMaterial().data() + destY * materialSize + destX; const QByteArray& srcMaterial = material->getContents(); const QVector<SharedObjectPointer> srcMaterials = material->getMaterials(); int srcSize = glm::sqrt((float)srcMaterial.size()); float srcIncrement = info.size / srcSize; QHash<int, int> materialMappings; if (srcIncrement == materialIncrement) { // easy case: same resolution int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; const uchar* src = (const uchar*)srcMaterial.constData() + srcY * srcSize + srcX; for (int y = 0; y < destHeight; y++, src += srcSize, dest += materialSize) { const uchar* lineSrc = src; for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrc++) { int value = *lineSrc; if (value != 0) { int& mapping = materialMappings[value]; if (mapping == 0) { mapping = getMaterialIndex(material->getMaterials().at(value - 1), _buffer->getMaterials(), _buffer->getMaterial()); } value = mapping; } *lineDest = value; } } } else { // more difficult: different resolutions float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; float srcAdvance = materialIncrement / srcIncrement; for (int y = 0; y < destHeight; y++, dest += materialSize, srcY += srcAdvance) { const uchar* src = (const uchar*)srcMaterial.constData() + (int)srcY * srcSize; float lineSrcX = srcX; for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) { int value = src[(int)lineSrcX]; if (value != 0) { int& mapping = materialMappings[value]; if (mapping == 0) { mapping = getMaterialIndex(material->getMaterials().at(value - 1), _buffer->getMaterials(), _buffer->getMaterial()); } value = mapping; } *lineDest = value; } } } clearUnusedMaterials(_buffer->getMaterials(), _buffer->getMaterial()); } } return false; } class HeightfieldRegionVisitor : public MetavoxelVisitor { public: QVector<Box> regions; Box regionBounds; HeightfieldRegionVisitor(const MetavoxelLOD& lod); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: void addRegion(const Box& unextended, const Box& extended); class DepthInfo { public: float minimumColorIncrement; float minimumMaterialIncrement; DepthInfo() : minimumColorIncrement(FLT_MAX), minimumMaterialIncrement(FLT_MAX) { } }; QVector<DepthInfo> _depthInfo; QVector<Box> _intersections; HeightfieldFetchVisitor _fetchVisitor; }; HeightfieldRegionVisitor::HeightfieldRegionVisitor(const MetavoxelLOD& lod) : MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute() << AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute() << Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() << Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod), regionBounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)), _fetchVisitor(lod, _intersections) { } int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) { DepthInfo depthInfo; HeightfieldColorDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>(); if (color) { int colorSize = glm::sqrt((float)color->getContents().size() / DataBlock::COLOR_BYTES); depthInfo.minimumColorIncrement = info.size / colorSize; } HeightfieldMaterialDataPointer material = info.inputValues.at(2).getInlineValue<HeightfieldMaterialDataPointer>(); if (material) { int materialSize = glm::sqrt((float)material->getContents().size()); depthInfo.minimumMaterialIncrement = info.size / materialSize;