mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 20:17:01 +02:00
Merge pull request #3256 from ey6es/metavoxels
Allow configurable block sizes, use back face culling for heightfields, custom expansion for spanner attributes, compute normals in vertex shader.
This commit is contained in:
commit
6976d0f51e
9 changed files with 165 additions and 63 deletions
|
@ -14,18 +14,26 @@
|
||||||
// the height texture
|
// the height texture
|
||||||
uniform sampler2D heightMap;
|
uniform sampler2D heightMap;
|
||||||
|
|
||||||
|
// the distance between height points in texture space
|
||||||
|
uniform float heightScale;
|
||||||
|
|
||||||
// the interpolated normal
|
// the interpolated normal
|
||||||
varying vec4 normal;
|
varying vec4 normal;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
// transform and store the normal for interpolation
|
// transform and store the normal for interpolation
|
||||||
normal = normalize(gl_ModelViewMatrix * vec4(0.0, 1.0, 0.0, 0.0));
|
vec2 heightCoord = gl_MultiTexCoord0.st;
|
||||||
|
float deltaX = texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r -
|
||||||
|
texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r;
|
||||||
|
float deltaZ = texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r -
|
||||||
|
texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r;
|
||||||
|
normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0));
|
||||||
|
|
||||||
// pass along the texture coordinates
|
// pass along the texture coordinates
|
||||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||||
|
|
||||||
// add the height to the position
|
// add the height to the position
|
||||||
float height = texture2D(heightMap, gl_MultiTexCoord0.st).r;
|
float height = texture2D(heightMap, heightCoord).r;
|
||||||
gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
|
gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0));
|
||||||
|
|
||||||
// the zero height should be invisible
|
// the zero height should be invisible
|
||||||
|
|
|
@ -359,9 +359,9 @@ void HeightfieldBuffer::render() {
|
||||||
int nextLineIndex = (i + 1) * sizeWithSkirt;
|
int nextLineIndex = (i + 1) * sizeWithSkirt;
|
||||||
for (int j = 0; j < rows; j++) {
|
for (int j = 0; j < rows; j++) {
|
||||||
*index++ = lineIndex + j;
|
*index++ = lineIndex + j;
|
||||||
*index++ = lineIndex + j + 1;
|
|
||||||
*index++ = nextLineIndex + j + 1;
|
|
||||||
*index++ = nextLineIndex + j;
|
*index++ = nextLineIndex + j;
|
||||||
|
*index++ = nextLineIndex + j + 1;
|
||||||
|
*index++ = lineIndex + j + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,6 +388,9 @@ void HeightfieldBuffer::render() {
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_2D, _colorTextureID);
|
glBindTexture(GL_TEXTURE_2D, _colorTextureID);
|
||||||
|
|
||||||
|
DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue(
|
||||||
|
DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize);
|
||||||
|
|
||||||
glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
|
glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
@ -405,6 +408,7 @@ QHash<int, HeightfieldBuffer::BufferPair> HeightfieldBuffer::_bufferPairs;
|
||||||
|
|
||||||
void HeightfieldPreview::render(const glm::vec3& translation, float scale) const {
|
void HeightfieldPreview::render(const glm::vec3& translation, float scale) const {
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
glEnable(GL_ALPHA_TEST);
|
glEnable(GL_ALPHA_TEST);
|
||||||
glAlphaFunc(GL_EQUAL, 0.0f);
|
glAlphaFunc(GL_EQUAL, 0.0f);
|
||||||
|
|
||||||
|
@ -431,6 +435,7 @@ void HeightfieldPreview::render(const glm::vec3& translation, float scale) const
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
|
||||||
glDisable(GL_ALPHA_TEST);
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,6 +473,7 @@ void DefaultMetavoxelRendererImplementation::init() {
|
||||||
_heightfieldProgram.bind();
|
_heightfieldProgram.bind();
|
||||||
_heightfieldProgram.setUniformValue("heightMap", 0);
|
_heightfieldProgram.setUniformValue("heightMap", 0);
|
||||||
_heightfieldProgram.setUniformValue("diffuseMap", 1);
|
_heightfieldProgram.setUniformValue("diffuseMap", 1);
|
||||||
|
_heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale");
|
||||||
_heightfieldProgram.release();
|
_heightfieldProgram.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -737,6 +743,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
|
||||||
|
|
||||||
_pointProgram.release();
|
_pointProgram.release();
|
||||||
|
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
glEnable(GL_ALPHA_TEST);
|
glEnable(GL_ALPHA_TEST);
|
||||||
glAlphaFunc(GL_EQUAL, 0.0f);
|
glAlphaFunc(GL_EQUAL, 0.0f);
|
||||||
|
|
||||||
|
@ -756,12 +763,14 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
|
||||||
glDisable(GL_ALPHA_TEST);
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram;
|
ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram;
|
||||||
int DefaultMetavoxelRendererImplementation::_pointScaleLocation;
|
int DefaultMetavoxelRendererImplementation::_pointScaleLocation;
|
||||||
ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram;
|
ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram;
|
||||||
|
int DefaultMetavoxelRendererImplementation::_heightScaleLocation;
|
||||||
|
|
||||||
static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
|
static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
|
||||||
GLdouble coefficients[] = { x, y, z, w };
|
GLdouble coefficients[] = { x, y, z, w };
|
||||||
|
|
|
@ -191,6 +191,7 @@ public:
|
||||||
static void init();
|
static void init();
|
||||||
|
|
||||||
static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; }
|
static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; }
|
||||||
|
static int getHeightScaleLocation() { return _heightScaleLocation; }
|
||||||
|
|
||||||
Q_INVOKABLE DefaultMetavoxelRendererImplementation();
|
Q_INVOKABLE DefaultMetavoxelRendererImplementation();
|
||||||
|
|
||||||
|
@ -204,6 +205,7 @@ private:
|
||||||
static int _pointScaleLocation;
|
static int _pointScaleLocation;
|
||||||
|
|
||||||
static ProgramObject _heightfieldProgram;
|
static ProgramObject _heightfieldProgram;
|
||||||
|
static int _heightScaleLocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Base class for spanner renderers; provides clipping.
|
/// Base class for spanner renderers; provides clipping.
|
||||||
|
|
|
@ -930,6 +930,13 @@ void HeightfieldTool::render() {
|
||||||
ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) :
|
ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) :
|
||||||
HeightfieldTool(editor, "Import Heightfield") {
|
HeightfieldTool(editor, "Import Heightfield") {
|
||||||
|
|
||||||
|
_form->addRow("Block Size:", _blockSize = new QSpinBox());
|
||||||
|
_blockSize->setPrefix("2^");
|
||||||
|
_blockSize->setMinimum(1);
|
||||||
|
_blockSize->setValue(5);
|
||||||
|
|
||||||
|
connect(_blockSize, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
||||||
|
&ImportHeightfieldTool::updatePreview);
|
||||||
_form->addRow("Height:", _height = new QPushButton());
|
_form->addRow("Height:", _height = new QPushButton());
|
||||||
connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile);
|
connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile);
|
||||||
_form->addRow("Color:", _color = new QPushButton());
|
_form->addRow("Color:", _color = new QPushButton());
|
||||||
|
@ -989,23 +996,22 @@ void ImportHeightfieldTool::selectColorFile() {
|
||||||
updatePreview();
|
updatePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
const int BLOCK_SIZE = 32;
|
|
||||||
const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1;
|
|
||||||
|
|
||||||
void ImportHeightfieldTool::updatePreview() {
|
void ImportHeightfieldTool::updatePreview() {
|
||||||
QVector<BufferDataPointer> buffers;
|
QVector<BufferDataPointer> buffers;
|
||||||
if (_heightImage.width() > 0 && _heightImage.height() > 0) {
|
if (_heightImage.width() > 0 && _heightImage.height() > 0) {
|
||||||
float z = 0.0f;
|
float z = 0.0f;
|
||||||
for (int i = 0; i < _heightImage.height(); i += BLOCK_ADVANCEMENT, z++) {
|
int blockSize = pow(2.0, _blockSize->value());
|
||||||
|
int blockAdvancement = blockSize - 1;
|
||||||
|
for (int i = 0; i < _heightImage.height(); i += blockAdvancement, z++) {
|
||||||
float x = 0.0f;
|
float x = 0.0f;
|
||||||
for (int j = 0; j < _heightImage.width(); j += BLOCK_ADVANCEMENT, x++) {
|
for (int j = 0; j < _heightImage.width(); j += blockAdvancement, x++) {
|
||||||
QByteArray height(BLOCK_SIZE * BLOCK_SIZE, 0);
|
QByteArray height(blockSize * blockSize, 0);
|
||||||
int rows = qMin(BLOCK_SIZE, _heightImage.height() - i);
|
int rows = qMin(blockSize, _heightImage.height() - i);
|
||||||
int columns = qMin(BLOCK_SIZE, _heightImage.width() - j);
|
int columns = qMin(blockSize, _heightImage.width() - j);
|
||||||
const int BYTES_PER_COLOR = 3;
|
const int BYTES_PER_COLOR = 3;
|
||||||
for (int y = 0; y < rows; y++) {
|
for (int y = 0; y < rows; y++) {
|
||||||
uchar* src = _heightImage.scanLine(i + y) + j * BYTES_PER_COLOR;
|
uchar* src = _heightImage.scanLine(i + y) + j * BYTES_PER_COLOR;
|
||||||
char* dest = height.data() + y * BLOCK_SIZE;
|
char* dest = height.data() + y * blockSize;
|
||||||
for (int x = 0; x < columns; x++) {
|
for (int x = 0; x < columns; x++) {
|
||||||
*dest++ = *src;
|
*dest++ = *src;
|
||||||
src += BYTES_PER_COLOR;
|
src += BYTES_PER_COLOR;
|
||||||
|
@ -1014,11 +1020,11 @@ void ImportHeightfieldTool::updatePreview() {
|
||||||
|
|
||||||
QByteArray color;
|
QByteArray color;
|
||||||
if (!_colorImage.isNull()) {
|
if (!_colorImage.isNull()) {
|
||||||
color = QByteArray(BLOCK_SIZE * BLOCK_SIZE * BYTES_PER_COLOR, 0);
|
color = QByteArray(blockSize * blockSize * BYTES_PER_COLOR, 0);
|
||||||
rows = qMax(0, qMin(BLOCK_SIZE, _colorImage.height() - i));
|
rows = qMax(0, qMin(blockSize, _colorImage.height() - i));
|
||||||
columns = qMax(0, qMin(BLOCK_SIZE, _colorImage.width() - j));
|
columns = qMax(0, qMin(blockSize, _colorImage.width() - j));
|
||||||
for (int y = 0; y < rows; y++) {
|
for (int y = 0; y < rows; y++) {
|
||||||
memcpy(color.data() + y * BLOCK_SIZE * BYTES_PER_COLOR,
|
memcpy(color.data() + y * blockSize * BYTES_PER_COLOR,
|
||||||
_colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR);
|
_colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,10 +267,11 @@ private slots:
|
||||||
|
|
||||||
void selectHeightFile();
|
void selectHeightFile();
|
||||||
void selectColorFile();
|
void selectColorFile();
|
||||||
|
void updatePreview();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void updatePreview();
|
QSpinBox* _blockSize;
|
||||||
|
|
||||||
QPushButton* _height;
|
QPushButton* _height;
|
||||||
QPushButton* _color;
|
QPushButton* _color;
|
||||||
|
|
|
@ -242,6 +242,30 @@ bool Attribute::metavoxelRootsEqual(const MetavoxelNode& firstRoot, const Metavo
|
||||||
return firstRoot.deepEquals(this, secondRoot, minimum, size, lod);
|
return firstRoot.deepEquals(this, secondRoot, minimum, size, lod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetavoxelNode* Attribute::expandMetavoxelRoot(const MetavoxelNode& root) {
|
||||||
|
AttributePointer attribute(this);
|
||||||
|
MetavoxelNode* newParent = new MetavoxelNode(attribute);
|
||||||
|
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
|
||||||
|
MetavoxelNode* newChild = new MetavoxelNode(attribute);
|
||||||
|
newParent->setChild(i, newChild);
|
||||||
|
int index = MetavoxelNode::getOppositeChildIndex(i);
|
||||||
|
if (root.isLeaf()) {
|
||||||
|
newChild->setChild(index, new MetavoxelNode(root.getAttributeValue(attribute)));
|
||||||
|
} else {
|
||||||
|
MetavoxelNode* grandchild = root.getChild(i);
|
||||||
|
grandchild->incrementReferenceCount();
|
||||||
|
newChild->setChild(index, grandchild);
|
||||||
|
}
|
||||||
|
for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) {
|
||||||
|
MetavoxelNode* newGrandchild = new MetavoxelNode(attribute);
|
||||||
|
newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild);
|
||||||
|
}
|
||||||
|
newChild->mergeChildren(attribute);
|
||||||
|
}
|
||||||
|
newParent->mergeChildren(attribute);
|
||||||
|
return newParent;
|
||||||
|
}
|
||||||
|
|
||||||
FloatAttribute::FloatAttribute(const QString& name, float defaultValue) :
|
FloatAttribute::FloatAttribute(const QString& name, float defaultValue) :
|
||||||
SimpleInlineAttribute<float>(name, defaultValue) {
|
SimpleInlineAttribute<float>(name, defaultValue) {
|
||||||
}
|
}
|
||||||
|
@ -559,9 +583,6 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead)
|
||||||
}
|
}
|
||||||
const QByteArray& childContents = child->getContents();
|
const QByteArray& childContents = child->getContents();
|
||||||
int childSize = glm::sqrt((float)childContents.size());
|
int childSize = glm::sqrt((float)childContents.size());
|
||||||
if (childSize != size) {
|
|
||||||
continue; // TODO: handle differently-sized children
|
|
||||||
}
|
|
||||||
const int INDEX_MASK = 1;
|
const int INDEX_MASK = 1;
|
||||||
int xIndex = i & INDEX_MASK;
|
int xIndex = i & INDEX_MASK;
|
||||||
const int Y_SHIFT = 1;
|
const int Y_SHIFT = 1;
|
||||||
|
@ -576,13 +597,33 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead)
|
||||||
char* dest = contents.data() + (zIndex * halfSize * size) + (xIndex * halfSize);
|
char* dest = contents.data() + (zIndex * halfSize * size) + (xIndex * halfSize);
|
||||||
uchar* src = (uchar*)childContents.data();
|
uchar* src = (uchar*)childContents.data();
|
||||||
int childSizePlusOne = childSize + 1;
|
int childSizePlusOne = childSize + 1;
|
||||||
for (int z = 0; z < halfSize; z++) {
|
if (childSize == size) {
|
||||||
for (char* end = dest + halfSize; dest != end; src += 2) {
|
// simple case: one destination value for four child values
|
||||||
int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne]));
|
for (int z = 0; z < halfSize; z++) {
|
||||||
*dest++ = (max == 0) ? 0 : (yOffset + (max >> 1));
|
for (char* end = dest + halfSize; dest != end; src += 2) {
|
||||||
|
int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne]));
|
||||||
|
*dest++ = (max == 0) ? 0 : (yOffset + (max >> 1));
|
||||||
|
}
|
||||||
|
dest += halfSize;
|
||||||
|
src += childSize;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// more complex: N destination values for four child values
|
||||||
|
int halfChildSize = childSize / 2;
|
||||||
|
int destPerSrc = size / childSize;
|
||||||
|
for (int z = 0; z < halfChildSize; z++) {
|
||||||
|
for (uchar* end = src + childSize; src != end; src += 2) {
|
||||||
|
int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne]));
|
||||||
|
memset(dest, (max == 0) ? 0 : (yOffset + (max >> 1)), destPerSrc);
|
||||||
|
dest += destPerSrc;
|
||||||
|
}
|
||||||
|
dest += halfSize;
|
||||||
|
for (int j = 1; j < destPerSrc; j++) {
|
||||||
|
memcpy(dest, dest - size, halfSize);
|
||||||
|
dest += size;
|
||||||
|
}
|
||||||
|
src += childSize;
|
||||||
}
|
}
|
||||||
dest += halfSize;
|
|
||||||
src += childSize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents));
|
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents));
|
||||||
|
@ -638,9 +679,6 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
|
||||||
}
|
}
|
||||||
const QByteArray& childContents = child->getContents();
|
const QByteArray& childContents = child->getContents();
|
||||||
int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL);
|
int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL);
|
||||||
if (childSize != size) {
|
|
||||||
continue; // TODO: handle differently-sized children
|
|
||||||
}
|
|
||||||
const int INDEX_MASK = 1;
|
const int INDEX_MASK = 1;
|
||||||
int xIndex = i & INDEX_MASK;
|
int xIndex = i & INDEX_MASK;
|
||||||
const int Y_SHIFT = 1;
|
const int Y_SHIFT = 1;
|
||||||
|
@ -653,7 +691,8 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
|
||||||
char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL;
|
char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL;
|
||||||
uchar* src = (uchar*)childContents.data();
|
uchar* src = (uchar*)childContents.data();
|
||||||
int childStride = childSize * BYTES_PER_PIXEL;
|
int childStride = childSize * BYTES_PER_PIXEL;
|
||||||
int halfStride = halfSize * BYTES_PER_PIXEL;
|
int stride = size * BYTES_PER_PIXEL;
|
||||||
|
int halfStride = stride / 2;
|
||||||
int childStep = 2 * BYTES_PER_PIXEL;
|
int childStep = 2 * BYTES_PER_PIXEL;
|
||||||
int redOffset3 = childStride + BYTES_PER_PIXEL;
|
int redOffset3 = childStride + BYTES_PER_PIXEL;
|
||||||
int greenOffset1 = BYTES_PER_PIXEL + 1;
|
int greenOffset1 = BYTES_PER_PIXEL + 1;
|
||||||
|
@ -662,14 +701,38 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
|
||||||
int blueOffset1 = BYTES_PER_PIXEL + 2;
|
int blueOffset1 = BYTES_PER_PIXEL + 2;
|
||||||
int blueOffset2 = childStride + 2;
|
int blueOffset2 = childStride + 2;
|
||||||
int blueOffset3 = childStride + BYTES_PER_PIXEL + 2;
|
int blueOffset3 = childStride + BYTES_PER_PIXEL + 2;
|
||||||
for (int z = 0; z < halfSize; z++) {
|
if (childSize == size) {
|
||||||
for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) {
|
// simple case: one destination value for four child values
|
||||||
*dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2;
|
for (int z = 0; z < halfSize; z++) {
|
||||||
*dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2;
|
for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) {
|
||||||
*dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2;
|
*dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2;
|
||||||
|
*dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2;
|
||||||
|
*dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2;
|
||||||
|
}
|
||||||
|
dest += halfStride;
|
||||||
|
src += childStride;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// more complex: N destination values for four child values
|
||||||
|
int halfChildSize = childSize / 2;
|
||||||
|
int destPerSrc = size / childSize;
|
||||||
|
for (int z = 0; z < halfChildSize; z++) {
|
||||||
|
for (uchar* end = src + childSize * BYTES_PER_PIXEL; src != end; src += childStep) {
|
||||||
|
*dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2;
|
||||||
|
*dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2;
|
||||||
|
*dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2;
|
||||||
|
for (int j = 1; j < destPerSrc; j++) {
|
||||||
|
memcpy(dest, dest - BYTES_PER_PIXEL, BYTES_PER_PIXEL);
|
||||||
|
dest += BYTES_PER_PIXEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dest += halfStride;
|
||||||
|
for (int j = 1; j < destPerSrc; j++) {
|
||||||
|
memcpy(dest, dest - stride, halfStride);
|
||||||
|
dest += stride;
|
||||||
|
}
|
||||||
|
src += childStride;
|
||||||
}
|
}
|
||||||
dest += halfStride;
|
|
||||||
src += childStride;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents));
|
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents));
|
||||||
|
@ -770,6 +833,29 @@ bool SharedObjectSetAttribute::deepEqual(void* first, void* second) const {
|
||||||
return setsEqual(decodeInline<SharedObjectSet>(first), decodeInline<SharedObjectSet>(second));
|
return setsEqual(decodeInline<SharedObjectSet>(first), decodeInline<SharedObjectSet>(second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MetavoxelNode* SharedObjectSetAttribute::expandMetavoxelRoot(const MetavoxelNode& root) {
|
||||||
|
AttributePointer attribute(this);
|
||||||
|
MetavoxelNode* newParent = new MetavoxelNode(attribute);
|
||||||
|
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
|
||||||
|
MetavoxelNode* newChild = new MetavoxelNode(root.getAttributeValue(attribute));
|
||||||
|
newParent->setChild(i, newChild);
|
||||||
|
if (root.isLeaf()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
MetavoxelNode* grandchild = root.getChild(i);
|
||||||
|
grandchild->incrementReferenceCount();
|
||||||
|
int index = MetavoxelNode::getOppositeChildIndex(i);
|
||||||
|
newChild->setChild(index, grandchild);
|
||||||
|
for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) {
|
||||||
|
MetavoxelNode* newGrandchild = new MetavoxelNode(attribute);
|
||||||
|
newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild);
|
||||||
|
}
|
||||||
|
newChild->mergeChildren(attribute);
|
||||||
|
}
|
||||||
|
newParent->mergeChildren(attribute);
|
||||||
|
return newParent;
|
||||||
|
}
|
||||||
|
|
||||||
bool SharedObjectSetAttribute::merge(void*& parent, void* children[], bool postRead) const {
|
bool SharedObjectSetAttribute::merge(void*& parent, void* children[], bool postRead) const {
|
||||||
for (int i = 0; i < MERGE_COUNT; i++) {
|
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||||
if (!decodeInline<SharedObjectSet>(children[i]).isEmpty()) {
|
if (!decodeInline<SharedObjectSet>(children[i]).isEmpty()) {
|
||||||
|
|
|
@ -238,6 +238,10 @@ public:
|
||||||
virtual bool metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot,
|
virtual bool metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot,
|
||||||
const glm::vec3& minimum, float size, const MetavoxelLOD& lod);
|
const glm::vec3& minimum, float size, const MetavoxelLOD& lod);
|
||||||
|
|
||||||
|
/// Expands the specified root, doubling its size in each dimension.
|
||||||
|
/// \return a new node representing the result
|
||||||
|
virtual MetavoxelNode* expandMetavoxelRoot(const MetavoxelNode& root);
|
||||||
|
|
||||||
/// Merges the value of a parent and its children.
|
/// Merges the value of a parent and its children.
|
||||||
/// \param postRead whether or not the merge is happening after a read
|
/// \param postRead whether or not the merge is happening after a read
|
||||||
/// \return whether or not the children and parent values are all equal
|
/// \return whether or not the children and parent values are all equal
|
||||||
|
@ -511,6 +515,8 @@ public:
|
||||||
|
|
||||||
virtual bool deepEqual(void* first, void* second) const;
|
virtual bool deepEqual(void* first, void* second) const;
|
||||||
|
|
||||||
|
virtual MetavoxelNode* expandMetavoxelRoot(const MetavoxelNode& root);
|
||||||
|
|
||||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||||
|
|
||||||
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
||||||
|
|
|
@ -512,33 +512,11 @@ void MetavoxelData::set(const glm::vec3& minimum, const MetavoxelData& data, boo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getOppositeIndex(int index) {
|
|
||||||
return index ^ MAXIMUM_FLAG_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MetavoxelData::expand() {
|
void MetavoxelData::expand() {
|
||||||
for (QHash<AttributePointer, MetavoxelNode*>::iterator it = _roots.begin(); it != _roots.end(); it++) {
|
for (QHash<AttributePointer, MetavoxelNode*>::iterator it = _roots.begin(); it != _roots.end(); it++) {
|
||||||
MetavoxelNode* newParent = new MetavoxelNode(it.key());
|
MetavoxelNode* newNode = it.key()->expandMetavoxelRoot(*it.value());
|
||||||
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
|
|
||||||
MetavoxelNode* newChild = new MetavoxelNode(it.key());
|
|
||||||
newParent->setChild(i, newChild);
|
|
||||||
int index = getOppositeIndex(i);
|
|
||||||
if (it.value()->isLeaf()) {
|
|
||||||
newChild->setChild(index, new MetavoxelNode(it.value()->getAttributeValue(it.key())));
|
|
||||||
} else {
|
|
||||||
MetavoxelNode* grandchild = it.value()->getChild(i);
|
|
||||||
grandchild->incrementReferenceCount();
|
|
||||||
newChild->setChild(index, grandchild);
|
|
||||||
}
|
|
||||||
for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) {
|
|
||||||
MetavoxelNode* newGrandchild = new MetavoxelNode(it.key());
|
|
||||||
newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild);
|
|
||||||
}
|
|
||||||
newChild->mergeChildren(it.key());
|
|
||||||
}
|
|
||||||
newParent->mergeChildren(it.key());
|
|
||||||
it.value()->decrementReferenceCount(it.key());
|
it.value()->decrementReferenceCount(it.key());
|
||||||
it.value() = newParent;
|
it.value() = newNode;
|
||||||
}
|
}
|
||||||
_size *= 2.0f;
|
_size *= 2.0f;
|
||||||
}
|
}
|
||||||
|
@ -823,6 +801,10 @@ void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) {
|
||||||
minimum = getNextMinimum(lastMinimum, size, index);
|
minimum = getNextMinimum(lastMinimum, size, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MetavoxelNode::getOppositeChildIndex(int index) {
|
||||||
|
return index ^ MAXIMUM_FLAG_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren) :
|
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren) :
|
||||||
_referenceCount(1) {
|
_referenceCount(1) {
|
||||||
|
|
||||||
|
|
|
@ -197,6 +197,8 @@ public:
|
||||||
|
|
||||||
static const int CHILD_COUNT = 8;
|
static const int CHILD_COUNT = 8;
|
||||||
|
|
||||||
|
static int getOppositeChildIndex(int index);
|
||||||
|
|
||||||
MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren = NULL);
|
MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren = NULL);
|
||||||
MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy);
|
MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue