Removed heightfield buffer code.

This commit is contained in:
Andrzej Kapolka 2014-11-14 17:18:34 -08:00
parent bba042e823
commit 479bea1eb2
2 changed files with 9 additions and 914 deletions

View file

@ -58,11 +58,6 @@ void MetavoxelSystem::init() {
MetavoxelClientManager::init();
DefaultMetavoxelRendererImplementation::init();
_heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(
new BufferDataAttribute("heightfieldBuffer"));
_heightfieldBufferAttribute->setLODThresholdMultiplier(
AttributeRegistry::getInstance()->getHeightfieldAttribute()->getLODThresholdMultiplier());
_voxelBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(
new BufferDataAttribute("voxelBuffer"));
_voxelBufferAttribute->setLODThresholdMultiplier(
@ -375,12 +370,6 @@ void MetavoxelSystem::renderVoxelCursor(const glm::vec3& position, float radius)
glDepthFunc(GL_LESS);
}
void MetavoxelSystem::deleteTextures(int heightID, int colorID, int textureID) {
glDeleteTextures(1, (GLuint*)&heightID);
glDeleteTextures(1, (GLuint*)&colorID);
glDeleteTextures(1, (GLuint*)&textureID);
}
class MaterialEditApplier : public SignalHandler {
public:
@ -670,357 +659,12 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) {
BufferData::~BufferData() {
}
const int HeightfieldBuffer::HEIGHT_BORDER = 1;
const int HeightfieldBuffer::SHARED_EDGE = 1;
const int HeightfieldBuffer::HEIGHT_EXTENSION = 2 * HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE;
HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale,
const QByteArray& height, const QByteArray& color, const QByteArray& material,
const QVector<SharedObjectPointer>& materials) :
_translation(translation),
_scale(scale),
_heightBounds(translation, translation + glm::vec3(scale, scale, scale)),
_colorBounds(_heightBounds),
_materialBounds(_heightBounds),
_height(height),
_color(color),
_material(material),
_materials(materials),
_heightTextureID(0),
_colorTextureID(0),
_materialTextureID(0),
_heightSize(glm::sqrt((float)height.size())),
_heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)),
_colorSize(glm::sqrt((float)color.size() / DataBlock::COLOR_BYTES)),
_colorIncrement(scale / (_colorSize - SHARED_EDGE)),
_materialSize(glm::sqrt((float)material.size())),
_materialIncrement(scale / (_materialSize - SHARED_EDGE)) {
_heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER;
_heightBounds.minimum.z -= _heightIncrement * HEIGHT_BORDER;
_heightBounds.maximum.x += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER);
_heightBounds.maximum.z += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER);
_colorBounds.maximum.x += _colorIncrement * SHARED_EDGE;
_colorBounds.maximum.z += _colorIncrement * SHARED_EDGE;
_materialBounds.maximum.x += _materialIncrement * SHARED_EDGE;
_materialBounds.maximum.z += _materialIncrement * SHARED_EDGE;
}
HeightfieldBuffer::~HeightfieldBuffer() {
// the textures have to be deleted on the main thread (for its opengl context)
if (QThread::currentThread() != Application::getInstance()->thread()) {
QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "deleteTextures",
Q_ARG(int, _heightTextureID), Q_ARG(int, _colorTextureID), Q_ARG(int, _materialTextureID));
} else {
glDeleteTextures(1, &_heightTextureID);
glDeleteTextures(1, &_colorTextureID);
glDeleteTextures(1, &_materialTextureID);
}
}
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 };
static const int EIGHT_BIT_MAXIMUM = 255;
static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / EIGHT_BIT_MAXIMUM;
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);
@ -1344,446 +988,6 @@ void DefaultMetavoxelRendererImplementation::init() {
DefaultMetavoxelRendererImplementation::DefaultMetavoxelRendererImplementation() {
}
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;
}
if (_depth < _depthInfo.size()) {
_depthInfo[_depth] = depthInfo;
} else {
_depthInfo.append(depthInfo);
}
if (!info.isLeaf) {
return _visitations.at(_depth).isInputLeaf(0) ? (DEFAULT_ORDER | ALL_NODES_REST) : DEFAULT_ORDER;
}
postVisit(info);
return STOP_RECURSION;
}
bool HeightfieldRegionVisitor::postVisit(MetavoxelInfo& info) {
const DepthInfo& depthInfo = _depthInfo.at(_depth);
if (_depth > 0) {
DepthInfo& parentDepthInfo = _depthInfo[_depth - 1];
parentDepthInfo.minimumColorIncrement = qMin(parentDepthInfo.minimumColorIncrement, depthInfo.minimumColorIncrement);
parentDepthInfo.minimumMaterialIncrement = qMin(parentDepthInfo.minimumMaterialIncrement,
depthInfo.minimumMaterialIncrement);
}
if (_visitations.at(_depth).isInputLeaf(0)) {
HeightfieldBuffer* buffer = NULL;
HeightfieldHeightDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldHeightDataPointer>();
if (height) {
int heightSize = glm::sqrt((float)height->getContents().size());
int extendedHeightSize = heightSize + HeightfieldBuffer::HEIGHT_EXTENSION;
int heightContentsSize = extendedHeightSize * extendedHeightSize;
float minimumColorIncrement = depthInfo.minimumColorIncrement;
float minimumMaterialIncrement = depthInfo.minimumMaterialIncrement;
for (int i = _depth - 1; i >= 0 && qMax(minimumColorIncrement, minimumMaterialIncrement) == FLT_MAX; i--) {
const DepthInfo& ancestorDepthInfo = _depthInfo.at(i);
minimumColorIncrement = qMin(minimumColorIncrement, ancestorDepthInfo.minimumColorIncrement);
minimumMaterialIncrement = qMin(minimumMaterialIncrement, ancestorDepthInfo.minimumMaterialIncrement);
}
int colorContentsSize = 0;
if (minimumColorIncrement != FLT_MAX) {
int colorSize = (int)glm::round(info.size / minimumColorIncrement) + HeightfieldBuffer::SHARED_EDGE;
colorContentsSize = colorSize * colorSize * DataBlock::COLOR_BYTES;
}
int materialContentsSize = 0;
if (minimumMaterialIncrement != FLT_MAX) {
int materialSize = (int)glm::round(info.size / minimumMaterialIncrement) + HeightfieldBuffer::SHARED_EDGE;
materialContentsSize = materialSize * materialSize;
}
const HeightfieldBuffer* existingBuffer = static_cast<const HeightfieldBuffer*>(
info.inputValues.at(3).getInlineValue<BufferDataPointer>().data());
Box bounds = info.getBounds();
if (existingBuffer && existingBuffer->getHeight().size() == heightContentsSize &&
existingBuffer->getColor().size() == colorContentsSize &&
existingBuffer->getMaterial().size() == materialContentsSize) {
// we already have a buffer of the correct resolution
addRegion(bounds, existingBuffer->getHeightBounds());
buffer = new HeightfieldBuffer(info.minimum, info.size, existingBuffer->getHeight(),
existingBuffer->getColor(), existingBuffer->getMaterial(), existingBuffer->getMaterials());
} else {
// we must create a new buffer and update its borders
buffer = new HeightfieldBuffer(info.minimum, info.size, QByteArray(heightContentsSize, 0),
QByteArray(colorContentsSize, 0), QByteArray(materialContentsSize, 0));
const Box& heightBounds = buffer->getHeightBounds();
addRegion(bounds, heightBounds);
_intersections.clear();
_intersections.append(Box(heightBounds.minimum,
glm::vec3(bounds.maximum.x, heightBounds.maximum.y, bounds.minimum.z)));
_intersections.append(Box(glm::vec3(bounds.maximum.x, heightBounds.minimum.y, heightBounds.minimum.z),
glm::vec3(heightBounds.maximum.x, heightBounds.maximum.y, bounds.maximum.z)));
_intersections.append(Box(glm::vec3(bounds.minimum.x, heightBounds.minimum.y, bounds.maximum.z),
heightBounds.maximum));
_intersections.append(Box(glm::vec3(heightBounds.minimum.x, heightBounds.minimum.y, bounds.minimum.z),
glm::vec3(bounds.minimum.x, heightBounds.maximum.y, heightBounds.maximum.z)));
_fetchVisitor.init(buffer);
_data->guide(_fetchVisitor);
}
}
BufferDataPointer pointer(buffer);
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer));
}
return true;
}
void HeightfieldRegionVisitor::addRegion(const Box& unextended, const Box& extended) {
regions.append(unextended);
regionBounds.add(extended);
}
class HeightfieldUpdateVisitor : public MetavoxelVisitor {
public:
HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions, const Box& regionBounds);
virtual int visit(MetavoxelInfo& info);
private:
const QVector<Box>& _regions;
const Box& _regionBounds;
QVector<Box> _intersections;
HeightfieldFetchVisitor _fetchVisitor;
};
HeightfieldUpdateVisitor::HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions,
const Box& regionBounds) :
MetavoxelVisitor(QVector<AttributePointer>() <<
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() <<
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod),
_regions(regions),
_regionBounds(regionBounds),
_fetchVisitor(lod, _intersections) {
}
int HeightfieldUpdateVisitor::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_regionBounds)) {
return STOP_RECURSION;
}
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
const HeightfieldBuffer* buffer = static_cast<const HeightfieldBuffer*>(
info.inputValues.at(0).getInlineValue<BufferDataPointer>().data());
if (!buffer) {
return STOP_RECURSION;
}
_intersections.clear();
foreach (const Box& region, _regions) {
if (region.intersects(buffer->getHeightBounds())) {
_intersections.append(region.getIntersection(buffer->getHeightBounds()));
}
}
if (_intersections.isEmpty()) {
return STOP_RECURSION;
}
HeightfieldBuffer* newBuffer = new HeightfieldBuffer(info.minimum, info.size,
buffer->getHeight(), buffer->getColor(), buffer->getMaterial(), buffer->getMaterials());
_fetchVisitor.init(newBuffer);
_data->guide(_fetchVisitor);
BufferDataPointer pointer(newBuffer);
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer));
return STOP_RECURSION;
}
class VoxelAugmentVisitor : public MetavoxelVisitor {
public:
@ -2392,27 +1596,13 @@ void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const
while (expandedPrevious.getSize() < data.getSize()) {
expandedPrevious.expand();
}
const AttributePointer& heightfieldBufferAttribute =
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute();
MetavoxelNode* root = expandedPrevious.getRoot(heightfieldBufferAttribute);
if (root) {
data.setRoot(heightfieldBufferAttribute, root);
root->incrementReferenceCount();
}
const AttributePointer& voxelBufferAttribute =
Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute();
root = expandedPrevious.getRoot(voxelBufferAttribute);
MetavoxelNode* root = expandedPrevious.getRoot(voxelBufferAttribute);
if (root) {
data.setRoot(voxelBufferAttribute, root);
root->incrementReferenceCount();
}
HeightfieldRegionVisitor heightfieldRegionVisitor(lod);
data.guideToDifferent(expandedPrevious, heightfieldRegionVisitor);
HeightfieldUpdateVisitor heightfieldUpdateVisitor(lod, heightfieldRegionVisitor.regions,
heightfieldRegionVisitor.regionBounds);
data.guide(heightfieldUpdateVisitor);
VoxelAugmentVisitor voxelAugmentVisitor(lod);
data.guideToDifferent(expandedPrevious, voxelAugmentVisitor);
}
@ -2535,19 +1725,6 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderHeightfields)) {
_baseHeightfieldProgram.bind();
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute());
data.guide(heightfieldRenderVisitor);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
_baseHeightfieldProgram.release();
}
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderDualContourSurfaces)) {
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
@ -2756,6 +1933,12 @@ void HeightfieldRenderer::init(Spanner* spanner) {
connect(heightfield, &Heightfield::materialChanged, this, &HeightfieldRenderer::applyMaterial);
}
class HeightfieldPoint {
public:
glm::vec3 vertex;
glm::vec2 textureCoord;
};
void HeightfieldRenderer::render(bool cursor) {
// create the buffer objects lazily
Heightfield* heightfield = static_cast<Heightfield*>(_spanner);
@ -2765,8 +1948,8 @@ void HeightfieldRenderer::render(bool cursor) {
int width = heightfield->getHeight()->getWidth();
int height = heightfield->getHeight()->getContents().size() / width;
int innerWidth = width - 2 * HeightfieldBuffer::HEIGHT_BORDER;
int innerHeight = height - 2 * HeightfieldBuffer::HEIGHT_BORDER;
int innerWidth = width - 2 * HeightfieldHeight::HEIGHT_BORDER;
int innerHeight = height - 2 * HeightfieldHeight::HEIGHT_BORDER;
int vertexCount = width * height;
int rows = height - 1;
int columns = width - 1;

View file

@ -78,8 +78,6 @@ public:
Q_INVOKABLE void setVoxelMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material);
Q_INVOKABLE void deleteTextures(int heightID, int colorID, int textureID);
signals:
void rendering();
@ -185,92 +183,6 @@ public:
typedef QExplicitlySharedDataPointer<BufferData> BufferDataPointer;
/// Contains the information necessary to render a heightfield block.
class HeightfieldBuffer : public BufferData {
public:
static const int HEIGHT_BORDER;
static const int SHARED_EDGE;
static const int HEIGHT_EXTENSION;
HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height,
const QByteArray& color, const QByteArray& material = QByteArray(),
const QVector<SharedObjectPointer>& materials = QVector<SharedObjectPointer>());
~HeightfieldBuffer();
const glm::vec3& getTranslation() const { return _translation; }
float getScale() const { return _scale; }
const Box& getHeightBounds() const { return _heightBounds; }
const Box& getColorBounds() const { return _colorBounds; }
const Box& getMaterialBounds() const { return _materialBounds; }
QByteArray& getHeight() { return _height; }
const QByteArray& getHeight() const { return _height; }
QByteArray& getColor() { return _color; }
const QByteArray& getColor() const { return _color; }
QByteArray& getMaterial() { return _material; }
const QByteArray& getMaterial() const { return _material; }
QVector<SharedObjectPointer>& getMaterials() { return _materials; }
const QVector<SharedObjectPointer>& getMaterials() const { return _materials; }
QByteArray getUnextendedHeight() const;
QByteArray getUnextendedColor(int x = 0, int y = 0) const;
int getHeightSize() const { return _heightSize; }
float getHeightIncrement() const { return _heightIncrement; }
int getColorSize() const { return _colorSize; }
float getColorIncrement() const { return _colorIncrement; }
int getMaterialSize() const { return _materialSize; }
float getMaterialIncrement() const { return _materialIncrement; }
virtual void render(bool cursor = false);
private:
glm::vec3 _translation;
float _scale;
Box _heightBounds;
Box _colorBounds;
Box _materialBounds;
QByteArray _height;
QByteArray _color;
QByteArray _material;
QVector<SharedObjectPointer> _materials;
GLuint _heightTextureID;
GLuint _colorTextureID;
GLuint _materialTextureID;
QVector<NetworkTexturePointer> _networkTextures;
int _heightSize;
float _heightIncrement;
int _colorSize;
float _colorIncrement;
int _materialSize;
float _materialIncrement;
typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair;
static QHash<int, BufferPair> _bufferPairs;
};
/// Convenience class for rendering a preview of a heightfield.
class HeightfieldPreview {
public:
void setBuffers(const QVector<BufferDataPointer>& buffers) { _buffers = buffers; }
const QVector<BufferDataPointer>& getBuffers() const { return _buffers; }
void render(const glm::vec3& translation, float scale) const;
private:
QVector<BufferDataPointer> _buffers;
};
/// Describes contents of a vertex in a voxel buffer.
class VoxelPoint {
public: