mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 07:12:40 +02:00
Partial subdivision implementation.
This commit is contained in:
parent
bc0fa0ed24
commit
34110b6745
2 changed files with 228 additions and 1 deletions
|
@ -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() {
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue