mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 04:13:32 +02:00
More texture progress.
This commit is contained in:
parent
a9c4ce2a6a
commit
3136e4df76
4 changed files with 197 additions and 40 deletions
|
@ -975,7 +975,7 @@ void ImportHeightfieldTool::apply() {
|
|||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer))));
|
||||
|
||||
QByteArray texture(height.size(), 0);
|
||||
HeightfieldDataPointer texturePointer(new HeightfieldData(texture));
|
||||
HeightfieldTextureDataPointer texturePointer(new HeightfieldTextureData(texture));
|
||||
data.setRoot(AttributeRegistry::getInstance()->getHeightfieldTextureAttribute(), new MetavoxelNode(AttributeValue(
|
||||
AttributeRegistry::getInstance()->getHeightfieldTextureAttribute(), encodeInline(texturePointer))));
|
||||
|
||||
|
|
|
@ -932,6 +932,108 @@ void HeightfieldColorData::set(const QImage& image) {
|
|||
memcpy(_contents.data(), image.constBits(), _contents.size());
|
||||
}
|
||||
|
||||
HeightfieldTextureData::HeightfieldTextureData(const QByteArray& contents) :
|
||||
HeightfieldData(contents) {
|
||||
}
|
||||
|
||||
HeightfieldTextureData::HeightfieldTextureData(Bitstream& in, int bytes) {
|
||||
read(in, bytes);
|
||||
}
|
||||
|
||||
HeightfieldTextureData::HeightfieldTextureData(Bitstream& in, int bytes, const HeightfieldTextureDataPointer& reference) {
|
||||
if (!reference) {
|
||||
read(in, bytes);
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&reference->getEncodedDeltaMutex());
|
||||
reference->setEncodedDelta(in.readAligned(bytes));
|
||||
reference->setDeltaData(HeightfieldDataPointer(this));
|
||||
_contents = reference->getContents();
|
||||
QImage image = decodeHeightfieldImage(reference->getEncodedDelta());
|
||||
if (image.isNull()) {
|
||||
return;
|
||||
}
|
||||
QPoint offset = image.offset();
|
||||
if (offset.x() == 0) {
|
||||
set(image);
|
||||
return;
|
||||
}
|
||||
int minX = offset.x() - 1;
|
||||
int minY = offset.y() - 1;
|
||||
int size = glm::sqrt((float)_contents.size());
|
||||
char* dest = _contents.data() + minY * size + minX;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
memcpy(dest, image.constScanLine(y), image.width());
|
||||
dest += size;
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldTextureData::write(Bitstream& out) {
|
||||
QMutexLocker locker(&_encodedMutex);
|
||||
if (_encoded.isEmpty()) {
|
||||
QImage image;
|
||||
int size = glm::sqrt((float)_contents.size());
|
||||
image = QImage((uchar*)_contents.data(), size, size, QImage::Format_Indexed8);
|
||||
_encoded = encodeHeightfieldImage(image, true);
|
||||
}
|
||||
out << _encoded.size();
|
||||
out.writeAligned(_encoded);
|
||||
}
|
||||
|
||||
void HeightfieldTextureData::writeDelta(Bitstream& out, const HeightfieldTextureDataPointer& reference) {
|
||||
if (!reference || reference->getContents().size() != _contents.size()) {
|
||||
write(out);
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&reference->getEncodedDeltaMutex());
|
||||
if (reference->getEncodedDelta().isEmpty() || reference->getDeltaData() != this) {
|
||||
QImage image;
|
||||
int size = glm::sqrt((float)_contents.size());
|
||||
int minX = size, minY = size;
|
||||
int maxX = -1, maxY = -1;
|
||||
const char* src = _contents.constData();
|
||||
const char* ref = reference->getContents().constData();
|
||||
for (int y = 0; y < size; y++) {
|
||||
bool difference = false;
|
||||
for (int x = 0; x < size; x++) {
|
||||
if (*src++ != *ref++) {
|
||||
minX = qMin(minX, x);
|
||||
maxX = qMax(maxX, x);
|
||||
difference = true;
|
||||
}
|
||||
}
|
||||
if (difference) {
|
||||
minY = qMin(minY, y);
|
||||
maxY = qMax(maxY, y);
|
||||
}
|
||||
}
|
||||
if (maxX >= minX) {
|
||||
int width = maxX - minX + 1;
|
||||
int height = maxY - minY + 1;
|
||||
image = QImage(width, height, QImage::Format_Indexed8);
|
||||
src = _contents.constData() + minY * size + minX;
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(image.scanLine(y), src, width);
|
||||
src += size;
|
||||
}
|
||||
}
|
||||
image.setOffset(QPoint(minX + 1, minY + 1));
|
||||
reference->setEncodedDelta(encodeHeightfieldImage(image, true));
|
||||
reference->setDeltaData(HeightfieldDataPointer(this));
|
||||
}
|
||||
out << reference->getEncodedDelta().size();
|
||||
out.writeAligned(reference->getEncodedDelta());
|
||||
}
|
||||
|
||||
void HeightfieldTextureData::read(Bitstream& in, int bytes) {
|
||||
set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)));
|
||||
}
|
||||
|
||||
void HeightfieldTextureData::set(const QImage& image) {
|
||||
_contents.resize(image.width() * image.height());
|
||||
memcpy(_contents.data(), image.constBits(), _contents.size());
|
||||
}
|
||||
|
||||
HeightfieldTexture::HeightfieldTexture() {
|
||||
}
|
||||
|
||||
|
@ -1199,35 +1301,70 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post
|
|||
}
|
||||
|
||||
HeightfieldTextureAttribute::HeightfieldTextureAttribute(const QString& name) :
|
||||
InlineAttribute<HeightfieldDataPointer>(name) {
|
||||
InlineAttribute<HeightfieldTextureDataPointer>(name) {
|
||||
}
|
||||
|
||||
void HeightfieldTextureAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
||||
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(HeightfieldTextureDataPointer*)&value = HeightfieldTextureDataPointer();
|
||||
} else {
|
||||
*(HeightfieldTextureDataPointer*)&value = HeightfieldTextureDataPointer(new HeightfieldTextureData(in, size));
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldTextureAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
||||
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
HeightfieldTextureDataPointer data = decodeInline<HeightfieldTextureDataPointer>(value);
|
||||
if (data) {
|
||||
data->write(out);
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldTextureAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const {
|
||||
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(HeightfieldTextureDataPointer*)&value = HeightfieldTextureDataPointer();
|
||||
} else {
|
||||
*(HeightfieldTextureDataPointer*)&value = HeightfieldTextureDataPointer(new HeightfieldTextureData(
|
||||
in, size, decodeInline<HeightfieldTextureDataPointer>(reference)));
|
||||
}
|
||||
}
|
||||
|
||||
void HeightfieldTextureAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const {
|
||||
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
HeightfieldTextureDataPointer data = decodeInline<HeightfieldTextureDataPointer>(value);
|
||||
if (data) {
|
||||
data->writeDelta(out, decodeInline<HeightfieldTextureDataPointer>(reference));
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool HeightfieldTextureAttribute::merge(void*& parent, void* children[], bool postRead) const {
|
||||
int maxSize = 0;
|
||||
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||
HeightfieldDataPointer pointer = decodeInline<HeightfieldDataPointer>(children[i]);
|
||||
HeightfieldTextureDataPointer pointer = decodeInline<HeightfieldTextureDataPointer>(children[i]);
|
||||
if (pointer) {
|
||||
maxSize = qMax(maxSize, pointer->getContents().size());
|
||||
}
|
||||
}
|
||||
if (maxSize == 0) {
|
||||
*(HeightfieldDataPointer*)&parent = HeightfieldDataPointer();
|
||||
*(HeightfieldTextureDataPointer*)&parent = HeightfieldTextureDataPointer();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -32,6 +32,7 @@ class Attribute;
|
|||
class HeightfieldColorData;
|
||||
class HeightfieldData;
|
||||
class HeightfieldHeightData;
|
||||
class HeightfieldTextureData;
|
||||
class MetavoxelData;
|
||||
class MetavoxelLOD;
|
||||
class MetavoxelNode;
|
||||
|
@ -520,6 +521,25 @@ private:
|
|||
void set(const QImage& image);
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<HeightfieldTextureData> HeightfieldTextureDataPointer;
|
||||
|
||||
/// Contains a block of heightfield texture data.
|
||||
class HeightfieldTextureData : public HeightfieldData {
|
||||
public:
|
||||
|
||||
HeightfieldTextureData(const QByteArray& contents);
|
||||
HeightfieldTextureData(Bitstream& in, int bytes);
|
||||
HeightfieldTextureData(Bitstream& in, int bytes, const HeightfieldTextureDataPointer& reference);
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const HeightfieldTextureDataPointer& reference);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes);
|
||||
void set(const QImage& image);
|
||||
};
|
||||
|
||||
/// Contains the description of a heightfield texture.
|
||||
class HeightfieldTexture : public SharedObject {
|
||||
Q_OBJECT
|
||||
|
@ -571,7 +591,7 @@ public:
|
|||
};
|
||||
|
||||
/// An attribute that stores heightfield textures.
|
||||
class HeightfieldTextureAttribute : public InlineAttribute<HeightfieldDataPointer> {
|
||||
class HeightfieldTextureAttribute : public InlineAttribute<HeightfieldTextureDataPointer> {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
|
@ -435,25 +435,18 @@ PaintHeightfieldColorEditVisitor::PaintHeightfieldColorEditVisitor(const PaintHe
|
|||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||
}
|
||||
|
||||
int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.getBounds().intersects(_bounds)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
HeightfieldColorDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldColorDataPointer>();
|
||||
static void paintColor(MetavoxelInfo& info, int index, const glm::vec3& position, float radius, const QColor& color) {
|
||||
HeightfieldColorDataPointer pointer = info.inputValues.at(index).getInlineValue<HeightfieldColorDataPointer>();
|
||||
if (!pointer) {
|
||||
return STOP_RECURSION;
|
||||
return;
|
||||
}
|
||||
QByteArray contents(pointer->getContents());
|
||||
const int BYTES_PER_PIXEL = 3;
|
||||
int size = glm::sqrt((float)contents.size() / BYTES_PER_PIXEL);
|
||||
int size = glm::sqrt((float)contents.size() / HeightfieldData::COLOR_BYTES);
|
||||
int highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
||||
glm::vec3 center = (_edit.position - info.minimum) * heightScale;
|
||||
float scaledRadius = _edit.radius * heightScale;
|
||||
glm::vec3 center = (position - info.minimum) * heightScale;
|
||||
float scaledRadius = radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
|
@ -462,14 +455,14 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
|
|||
// paint all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||
int stride = size * BYTES_PER_PIXEL;
|
||||
char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL;
|
||||
int stride = size * HeightfieldData::COLOR_BYTES;
|
||||
char* lineDest = contents.data() + (int)z * stride + (int)startX * HeightfieldData::COLOR_BYTES;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
char red = _edit.color.red(), green = _edit.color.green(), blue = _edit.color.blue();
|
||||
char red = color.red(), green = color.green(), blue = color.blue();
|
||||
bool changed = false;
|
||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||
char* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) {
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest += HeightfieldData::COLOR_BYTES) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
dest[0] = red;
|
||||
|
@ -482,8 +475,19 @@ int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
|
|||
}
|
||||
if (changed) {
|
||||
HeightfieldColorDataPointer newPointer(new HeightfieldColorData(contents));
|
||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldColorDataPointer>(newPointer));
|
||||
info.outputValues[index] = AttributeValue(info.inputValues.at(index).getAttribute(),
|
||||
encodeInline<HeightfieldColorDataPointer>(newPointer));
|
||||
}
|
||||
}
|
||||
|
||||
int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.getBounds().intersects(_bounds)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
paintColor(info, 0, _edit.position, _edit.radius, _edit.color);
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
|
@ -531,13 +535,12 @@ int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
|
|||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
HeightfieldColorDataPointer pointer = info.inputValues.at(1).getInlineValue<HeightfieldColorDataPointer>();
|
||||
HeightfieldTextureDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldTextureDataPointer>();
|
||||
if (!pointer) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
QByteArray contents(pointer->getContents());
|
||||
const int BYTES_PER_PIXEL = 3;
|
||||
int size = glm::sqrt((float)contents.size() / BYTES_PER_PIXEL);
|
||||
int size = glm::sqrt((float)contents.size());
|
||||
int highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
||||
|
@ -551,28 +554,25 @@ int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
|
|||
// paint all points within the radius
|
||||
float z = qMax(start.z, 0.0f);
|
||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||
int stride = size * BYTES_PER_PIXEL;
|
||||
char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL;
|
||||
char* lineDest = contents.data() + (int)z * size + (int)startX;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
char red = _edit.averageColor.red(), green = _edit.averageColor.green(), blue = _edit.averageColor.blue();
|
||||
bool changed = false;
|
||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||
char* dest = lineDest;
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) {
|
||||
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
dest[0] = red;
|
||||
dest[1] = green;
|
||||
dest[2] = blue;
|
||||
*dest = 1;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
lineDest += stride;
|
||||
lineDest += size;
|
||||
}
|
||||
if (changed) {
|
||||
HeightfieldColorDataPointer newPointer(new HeightfieldColorData(contents));
|
||||
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<HeightfieldColorDataPointer>(newPointer));
|
||||
HeightfieldTextureDataPointer newPointer(new HeightfieldTextureData(contents));
|
||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldTextureDataPointer>(newPointer));
|
||||
}
|
||||
paintColor(info, 1, _edit.position, _edit.radius, _edit.averageColor);
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue