mirror of
https://github.com/lubosz/overte.git
synced 2025-04-16 10:46:45 +02:00
Allow configurable block sizes, merging children with different resolutions.
This commit is contained in:
parent
d552b7ca97
commit
f8afdba922
3 changed files with 81 additions and 35 deletions
|
@ -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;
|
||||
|
|
|
@ -559,9 +559,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 +573,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 +655,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 +667,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 +677,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));
|
||||
|
|
Loading…
Reference in a new issue