mirror of
https://github.com/lubosz/overte.git
synced 2025-04-16 15:30:11 +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
|
||||
uniform sampler2D heightMap;
|
||||
|
||||
// the distance between height points in texture space
|
||||
uniform float heightScale;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// 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
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
|
||||
// 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));
|
||||
|
||||
// the zero height should be invisible
|
||||
|
|
|
@ -359,9 +359,9 @@ void HeightfieldBuffer::render() {
|
|||
int nextLineIndex = (i + 1) * sizeWithSkirt;
|
||||
for (int j = 0; j < rows; j++) {
|
||||
*index++ = lineIndex + j;
|
||||
*index++ = lineIndex + j + 1;
|
||||
*index++ = nextLineIndex + j + 1;
|
||||
*index++ = nextLineIndex + j;
|
||||
*index++ = nextLineIndex + j + 1;
|
||||
*index++ = lineIndex + j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,6 +388,9 @@ void HeightfieldBuffer::render() {
|
|||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, _colorTextureID);
|
||||
|
||||
DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue(
|
||||
DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize);
|
||||
|
||||
glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 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 {
|
||||
glDisable(GL_BLEND);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_EQUAL, 0.0f);
|
||||
|
||||
|
@ -431,6 +435,7 @@ void HeightfieldPreview::render(const glm::vec3& translation, float scale) const
|
|||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
|
@ -468,6 +473,7 @@ void DefaultMetavoxelRendererImplementation::init() {
|
|||
_heightfieldProgram.bind();
|
||||
_heightfieldProgram.setUniformValue("heightMap", 0);
|
||||
_heightfieldProgram.setUniformValue("diffuseMap", 1);
|
||||
_heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale");
|
||||
_heightfieldProgram.release();
|
||||
}
|
||||
}
|
||||
|
@ -737,6 +743,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
|
|||
|
||||
_pointProgram.release();
|
||||
|
||||
glEnable(GL_CULL_FACE);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_EQUAL, 0.0f);
|
||||
|
||||
|
@ -756,12 +763,14 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
|
|||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram;
|
||||
int DefaultMetavoxelRendererImplementation::_pointScaleLocation;
|
||||
ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram;
|
||||
int DefaultMetavoxelRendererImplementation::_heightScaleLocation;
|
||||
|
||||
static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
|
||||
GLdouble coefficients[] = { x, y, z, w };
|
||||
|
|
|
@ -191,6 +191,7 @@ public:
|
|||
static void init();
|
||||
|
||||
static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; }
|
||||
static int getHeightScaleLocation() { return _heightScaleLocation; }
|
||||
|
||||
Q_INVOKABLE DefaultMetavoxelRendererImplementation();
|
||||
|
||||
|
@ -204,6 +205,7 @@ private:
|
|||
static int _pointScaleLocation;
|
||||
|
||||
static ProgramObject _heightfieldProgram;
|
||||
static int _heightScaleLocation;
|
||||
};
|
||||
|
||||
/// Base class for spanner renderers; provides clipping.
|
||||
|
|
|
@ -930,6 +930,13 @@ void HeightfieldTool::render() {
|
|||
ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) :
|
||||
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());
|
||||
connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile);
|
||||
_form->addRow("Color:", _color = new QPushButton());
|
||||
|
@ -989,23 +996,22 @@ void ImportHeightfieldTool::selectColorFile() {
|
|||
updatePreview();
|
||||
}
|
||||
|
||||
const int BLOCK_SIZE = 32;
|
||||
const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1;
|
||||
|
||||
void ImportHeightfieldTool::updatePreview() {
|
||||
QVector<BufferDataPointer> buffers;
|
||||
if (_heightImage.width() > 0 && _heightImage.height() > 0) {
|
||||
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;
|
||||
for (int j = 0; j < _heightImage.width(); j += BLOCK_ADVANCEMENT, x++) {
|
||||
QByteArray height(BLOCK_SIZE * BLOCK_SIZE, 0);
|
||||
int rows = qMin(BLOCK_SIZE, _heightImage.height() - i);
|
||||
int columns = qMin(BLOCK_SIZE, _heightImage.width() - j);
|
||||
for (int j = 0; j < _heightImage.width(); j += blockAdvancement, x++) {
|
||||
QByteArray height(blockSize * blockSize, 0);
|
||||
int rows = qMin(blockSize, _heightImage.height() - i);
|
||||
int columns = qMin(blockSize, _heightImage.width() - j);
|
||||
const int BYTES_PER_COLOR = 3;
|
||||
for (int y = 0; y < rows; y++) {
|
||||
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++) {
|
||||
*dest++ = *src;
|
||||
src += BYTES_PER_COLOR;
|
||||
|
@ -1014,11 +1020,11 @@ void ImportHeightfieldTool::updatePreview() {
|
|||
|
||||
QByteArray color;
|
||||
if (!_colorImage.isNull()) {
|
||||
color = QByteArray(BLOCK_SIZE * BLOCK_SIZE * BYTES_PER_COLOR, 0);
|
||||
rows = qMax(0, qMin(BLOCK_SIZE, _colorImage.height() - i));
|
||||
columns = qMax(0, qMin(BLOCK_SIZE, _colorImage.width() - j));
|
||||
color = QByteArray(blockSize * blockSize * BYTES_PER_COLOR, 0);
|
||||
rows = qMax(0, qMin(blockSize, _colorImage.height() - i));
|
||||
columns = qMax(0, qMin(blockSize, _colorImage.width() - j));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -267,10 +267,11 @@ private slots:
|
|||
|
||||
void selectHeightFile();
|
||||
void selectColorFile();
|
||||
|
||||
void updatePreview();
|
||||
|
||||
private:
|
||||
|
||||
void updatePreview();
|
||||
QSpinBox* _blockSize;
|
||||
|
||||
QPushButton* _height;
|
||||
QPushButton* _color;
|
||||
|
|
|
@ -242,6 +242,30 @@ bool Attribute::metavoxelRootsEqual(const MetavoxelNode& firstRoot, const Metavo
|
|||
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) :
|
||||
SimpleInlineAttribute<float>(name, defaultValue) {
|
||||
}
|
||||
|
@ -559,9 +583,6 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead)
|
|||
}
|
||||
const QByteArray& childContents = child->getContents();
|
||||
int childSize = glm::sqrt((float)childContents.size());
|
||||
if (childSize != size) {
|
||||
continue; // TODO: handle differently-sized children
|
||||
}
|
||||
const int INDEX_MASK = 1;
|
||||
int xIndex = i & INDEX_MASK;
|
||||
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);
|
||||
uchar* src = (uchar*)childContents.data();
|
||||
int childSizePlusOne = childSize + 1;
|
||||
for (int z = 0; z < halfSize; z++) {
|
||||
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));
|
||||
if (childSize == size) {
|
||||
// simple case: one destination value for four child values
|
||||
for (int z = 0; z < halfSize; z++) {
|
||||
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));
|
||||
|
@ -638,9 +679,6 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
|
|||
}
|
||||
const QByteArray& childContents = child->getContents();
|
||||
int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL);
|
||||
if (childSize != size) {
|
||||
continue; // TODO: handle differently-sized children
|
||||
}
|
||||
const int INDEX_MASK = 1;
|
||||
int xIndex = i & INDEX_MASK;
|
||||
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;
|
||||
uchar* src = (uchar*)childContents.data();
|
||||
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 redOffset3 = childStride + BYTES_PER_PIXEL;
|
||||
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 blueOffset2 = childStride + 2;
|
||||
int blueOffset3 = childStride + BYTES_PER_PIXEL + 2;
|
||||
for (int z = 0; z < halfSize; z++) {
|
||||
for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != 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;
|
||||
if (childSize == size) {
|
||||
// simple case: one destination value for four child values
|
||||
for (int z = 0; z < halfSize; z++) {
|
||||
for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != 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;
|
||||
}
|
||||
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));
|
||||
|
@ -770,6 +833,29 @@ bool SharedObjectSetAttribute::deepEqual(void* first, void* second) const {
|
|||
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 {
|
||||
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||
if (!decodeInline<SharedObjectSet>(children[i]).isEmpty()) {
|
||||
|
|
|
@ -238,6 +238,10 @@ public:
|
|||
virtual bool metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot,
|
||||
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.
|
||||
/// \param postRead whether or not the merge is happening after a read
|
||||
/// \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 MetavoxelNode* expandMetavoxelRoot(const MetavoxelNode& root);
|
||||
|
||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) 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() {
|
||||
for (QHash<AttributePointer, MetavoxelNode*>::iterator it = _roots.begin(); it != _roots.end(); it++) {
|
||||
MetavoxelNode* newParent = new MetavoxelNode(it.key());
|
||||
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());
|
||||
MetavoxelNode* newNode = it.key()->expandMetavoxelRoot(*it.value());
|
||||
it.value()->decrementReferenceCount(it.key());
|
||||
it.value() = newParent;
|
||||
it.value() = newNode;
|
||||
}
|
||||
_size *= 2.0f;
|
||||
}
|
||||
|
@ -823,6 +801,10 @@ void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) {
|
|||
minimum = getNextMinimum(lastMinimum, size, index);
|
||||
}
|
||||
|
||||
int MetavoxelNode::getOppositeChildIndex(int index) {
|
||||
return index ^ MAXIMUM_FLAG_MASK;
|
||||
}
|
||||
|
||||
MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren) :
|
||||
_referenceCount(1) {
|
||||
|
||||
|
|
|
@ -197,6 +197,8 @@ public:
|
|||
|
||||
static const int CHILD_COUNT = 8;
|
||||
|
||||
static int getOppositeChildIndex(int index);
|
||||
|
||||
MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren = NULL);
|
||||
MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy);
|
||||
|
||||
|
|
Loading…
Reference in a new issue