Partial subdivision implementation.

This commit is contained in:
Andrzej Kapolka 2015-01-23 18:19:45 -08:00
parent bc0fa0ed24
commit 34110b6745
2 changed files with 228 additions and 1 deletions

View file

@ -1846,6 +1846,13 @@ HeightfieldNode* HeightfieldNode::paintHeight(const glm::vec3& translation, cons
new HeightfieldStack(stackWidth, newStackContents, newStackMaterials)));
}
// if the granularity is insufficient, we must subdivide
if (scale.x / innerHeightWidth > granularity || scale.z / innerHeightHeight > granularity) {
HeightfieldNodePointer newNode(subdivide(newHeightContents, newStackContents));
return newNode->paintHeight(translation, rotation, scale, position, radius, height, set,
erase, 1.0f, 0.0f, granularity);
}
// now apply the actual change
glm::vec3 start = glm::clamp(glm::floor(center - extents), glm::vec3(),
glm::vec3((float)highestHeightX, 0.0f, (float)highestHeightZ));
@ -1927,9 +1934,15 @@ HeightfieldNode* HeightfieldNode::fillHeight(const glm::vec3& translation, const
if (!_stack) {
return this;
}
QVector<quint16> newHeightContents = _height->getContents();
// if the granularity is insufficient, we must subdivide
QVector<quint16> newHeightContents = _height->getContents();
QVector<StackArray> newStackContents = _stack->getContents();
if (scale.x / innerHeightWidth > granularity || scale.z / innerHeightHeight > granularity) {
HeightfieldNodePointer newNode(subdivide(newHeightContents, newStackContents));
return newNode->fillHeight(translation, rotation, scale, position, radius, granularity);
}
int stackWidth = _stack->getWidth();
int stackHeight = newStackContents.size() / stackWidth;
QVector<SharedObjectPointer> newStackMaterials = _stack->getMaterials();
@ -2149,6 +2162,14 @@ HeightfieldNode* HeightfieldNode::setMaterial(const glm::vec3& translation, cons
return new HeightfieldNode(HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, newHeightContents)),
_color, _material, HeightfieldStackPointer(new HeightfieldStack(stackWidth, newStackContents, newStackMaterials)));
}
// if the granularity is insufficient, we must subdivide
if (scale.x / innerHeightWidth > granularity || scale.z / innerHeightHeight > granularity) {
HeightfieldNodePointer newNode(subdivide(newHeightContents, newStackContents));
return newNode->setMaterial(translation, rotation, scale, spanner, material, color,
paint, voxelize, 1.0f, 0.0f, granularity);
}
QVector<quint16> oldHeightContents = newHeightContents;
QVector<StackArray> oldStackContents = newStackContents;
@ -3210,6 +3231,210 @@ bool HeightfieldNode::findHeightfieldRayIntersection(const glm::vec3& origin, co
return false;
}
static inline float mixHeights(float firstHeight, float secondHeight, float t) {
return (firstHeight == 0.0f) ? secondHeight : (secondHeight == 0.0f ? firstHeight :
glm::mix(firstHeight, secondHeight, t));
}
HeightfieldNode* HeightfieldNode::subdivide(const QVector<quint16>& heightContents,
const QVector<StackArray>& stackContents) const {
HeightfieldNode* newNode = new HeightfieldNode(*this);
int heightWidth = _height->getWidth();
int heightHeight = heightContents.size() / heightWidth;
newNode->setHeight(HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, heightContents)));
int stackWidth = 0, stackHeight = 0;
QVector<SharedObjectPointer> stackMaterials;
if (_stack) {
stackWidth = _stack->getWidth();
stackHeight = stackContents.size() / stackWidth;
stackMaterials = _stack->getMaterials();
newNode->setStack(HeightfieldStackPointer(new HeightfieldStack(stackWidth, stackContents, stackMaterials)));
}
int colorWidth = 0, colorHeight = 0;
if (_color) {
colorWidth = _color->getWidth();
colorHeight = _color->getContents().size() / (colorWidth * DataBlock::COLOR_BYTES);
}
int materialWidth = 0, materialHeight = 0;
QVector<SharedObjectPointer> materialMaterials;
if (_material) {
materialWidth = _material->getWidth();
materialHeight = _material->getContents().size() / materialWidth;
materialMaterials = _material->getMaterials();
}
for (int i = 0; i < CHILD_COUNT; i++) {
QVector<quint16> childHeightContents(heightWidth * heightHeight);
QByteArray childColorContents(colorWidth * colorHeight * DataBlock::COLOR_BYTES, 0xFF);
QByteArray childMaterialContents(materialWidth * materialHeight, 0);
QVector<StackArray> childStackContents(stackWidth * stackHeight);
quint16* heightDest = childHeightContents.data();
const quint16* heightSrc = heightContents.constData() + (i & Y_MAXIMUM_FLAG ? (heightHeight / 2) * heightWidth : 0) +
(i & X_MAXIMUM_FLAG ? heightWidth / 2 : 0);
for (int z = 0; z < heightHeight; z++) {
float srcZ = z * 0.5f + 0.5f;
float fractZ = glm::fract(srcZ);
const quint16* heightSrcZ = heightSrc + (int)srcZ * heightWidth;
for (int x = 0; x < heightWidth; x++) {
float srcX = x * 0.5f + 0.5f;
float fractX = glm::fract(srcX);
const quint16* heightSrcX = heightSrcZ + (int)srcX;
if (fractZ == 0.0f) {
if (fractX == 0.0f) {
*heightDest++ = heightSrcX[0];
} else {
*heightDest++ = mixHeights(heightSrcX[0], heightSrcX[1], fractX);
}
} else {
if (fractX == 0.0f) {
*heightDest++ = mixHeights(heightSrcX[0], heightSrcX[heightWidth], fractZ);
} else {
*heightDest++ = mixHeights(mixHeights(heightSrcX[0], heightSrcX[1], fractX),
mixHeights(heightSrcX[heightWidth], heightSrcX[heightWidth + 1], fractX), fractZ);
}
}
}
}
if (colorWidth != 0) {
char* colorDest = childColorContents.data();
const uchar* colorSrc = (const uchar*)_color->getContents().constData() +
((i & Y_MAXIMUM_FLAG ? (colorHeight / 2) * colorWidth : 0) +
(i & X_MAXIMUM_FLAG ? colorWidth / 2 : 0)) * DataBlock::COLOR_BYTES;
for (int z = 0; z < colorHeight; z++) {
float srcZ = z * 0.5f;
float fractZ = glm::fract(srcZ);
const uchar* colorSrcZ = colorSrc + (int)srcZ * colorWidth * DataBlock::COLOR_BYTES;
for (int x = 0; x < colorWidth; x++) {
float srcX = x * 0.5f;
float fractX = glm::fract(srcX);
const uchar* colorSrcX = colorSrcZ + (int)srcX * DataBlock::COLOR_BYTES;
const uchar* nextColorSrcX = colorSrcX + colorWidth * DataBlock::COLOR_BYTES;
if (fractZ == 0.0f) {
if (fractX == 0.0f) {
*colorDest++ = colorSrcX[0];
*colorDest++ = colorSrcX[1];
*colorDest++ = colorSrcX[2];
} else {
*colorDest++ = glm::mix(colorSrcX[0], colorSrcX[3], fractX);
*colorDest++ = glm::mix(colorSrcX[1], colorSrcX[4], fractX);
*colorDest++ = glm::mix(colorSrcX[2], colorSrcX[5], fractX);
}
} else {
if (fractX == 0.0f) {
*colorDest++ = glm::mix(colorSrcX[0], nextColorSrcX[0], fractZ);
*colorDest++ = glm::mix(colorSrcX[1], nextColorSrcX[1], fractZ);
*colorDest++ = glm::mix(colorSrcX[2], nextColorSrcX[2], fractZ);
} else {
*colorDest++ = glm::mix(glm::mix(colorSrcX[0], colorSrcX[3], fractX),
glm::mix(nextColorSrcX[0], nextColorSrcX[3], fractX), fractZ);
*colorDest++ = glm::mix(glm::mix(colorSrcX[1], colorSrcX[4], fractX),
glm::mix(nextColorSrcX[1], nextColorSrcX[4], fractX), fractZ);
*colorDest++ = glm::mix(glm::mix(colorSrcX[2], colorSrcX[5], fractX),
glm::mix(nextColorSrcX[2], nextColorSrcX[5], fractX), fractZ);
}
}
}
}
}
if (materialWidth != 0) {
char* materialDest = childMaterialContents.data();
const char* materialSrc = _material->getContents().constData() +
(i & Y_MAXIMUM_FLAG ? (materialHeight / 2) * materialWidth : 0) +
(i & X_MAXIMUM_FLAG ? materialWidth / 2 : 0);
for (int z = 0; z < materialHeight; z++) {
float srcZ = z * 0.5f;
const char* materialSrcZ = materialSrc + (int)srcZ * materialWidth;
for (int x = 0; x < materialWidth; x++) {
float srcX = x * 0.5f;
const char* materialSrcX = materialSrcZ + (int)srcX;
*materialDest++ = *materialSrcX;
}
}
}
if (stackWidth != 0) {
StackArray* stackDest = childStackContents.data();
const StackArray* stackSrc = _stack->getContents().constData() +
(i & Y_MAXIMUM_FLAG ? (stackHeight / 2) * stackWidth : 0) +
(i & X_MAXIMUM_FLAG ? stackWidth / 2 : 0);
for (int z = 0; z < stackHeight; z++) {
float srcZ = z * 0.5f;
float fractZ = glm::fract(srcZ);
const StackArray* stackSrcZ = stackSrc + (int)srcZ * stackWidth;
for (int x = 0; x < stackWidth; x++) {
float srcX = x * 0.5f;
float fractX = glm::fract(srcX);
const StackArray* stackSrcX = stackSrcZ + (int)srcX;
if (stackSrcX->isEmpty()) {
stackDest++;
continue;
}
int minimumY = stackSrcX->getPosition() * 2;
int maximumY = (stackSrcX->getPosition() + stackSrcX->getEntryCount() - 1) * 2;
*stackDest = StackArray(maximumY - minimumY + 1);
stackDest->setPosition(minimumY);
for (int y = minimumY; y <= maximumY; y++) {
float srcY = y * 0.5f;
float fractY = glm::fract(srcY);
const StackArray::Entry& srcEntry = stackSrcX->getEntry((int)srcY);
StackArray::Entry& destEntry = stackDest->getEntry(y);
destEntry.color = srcEntry.color;
destEntry.material = srcEntry.material;
if (srcEntry.hermiteX != 0) {
glm::vec3 normal;
float distance = srcEntry.getHermiteX(normal);
if (distance < fractX) {
const StackArray::Entry& nextSrcEntryX = stackSrcX[1].getEntry((int)srcY);
destEntry.color = nextSrcEntryX.color;
destEntry.material = nextSrcEntryX.material;
} else {
destEntry.setHermiteX(normal, (distance - fractX) / 0.5f);
}
}
if (srcEntry.hermiteY != 0) {
glm::vec3 normal;
float distance = srcEntry.getHermiteY(normal);
if (distance < fractY) {
const StackArray::Entry& nextSrcEntryY = stackSrcX->getEntry((int)srcY + 1);
destEntry.color = nextSrcEntryY.color;
destEntry.material = nextSrcEntryY.material;
} else {
destEntry.setHermiteY(normal, (distance - fractY) / 0.5f);
}
}
if (srcEntry.hermiteZ != 0) {
glm::vec3 normal;
float distance = srcEntry.getHermiteZ(normal);
if (distance < fractZ) {
const StackArray::Entry& nextSrcEntryZ = stackSrcX[stackWidth].getEntry((int)srcY);
destEntry.color = nextSrcEntryZ.color;
destEntry.material = nextSrcEntryZ.material;
} else {
destEntry.setHermiteZ(normal, (distance - fractZ) / 0.5f);
}
}
}
stackDest++;
}
}
}
newNode->setChild(i, HeightfieldNodePointer(new HeightfieldNode(
HeightfieldHeightPointer(new HeightfieldHeight(heightWidth, childHeightContents)),
HeightfieldColorPointer(colorWidth == 0 ? NULL : new HeightfieldColor(colorWidth, childColorContents)),
HeightfieldMaterialPointer(materialWidth == 0 ? NULL :
new HeightfieldMaterial(materialWidth, childMaterialContents, materialMaterials)),
HeightfieldStackPointer(stackWidth == 0 ? NULL :
new HeightfieldStack(stackWidth, childStackContents, stackMaterials)))));
}
return newNode;
}
AbstractHeightfieldNodeRenderer::~AbstractHeightfieldNodeRenderer() {
}

View file

@ -737,6 +737,8 @@ private:
bool findHeightfieldRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
float boundsDistance, float& distance) const;
HeightfieldNode* subdivide(const QVector<quint16>& heightContents, const QVector<StackArray>& stackContents) const;
HeightfieldHeightPointer _height;
HeightfieldColorPointer _color;
HeightfieldMaterialPointer _material;