mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 15:59:49 +02:00
More texture bits.
This commit is contained in:
parent
3136e4df76
commit
540d074270
3 changed files with 83 additions and 14 deletions
|
@ -932,8 +932,9 @@ void HeightfieldColorData::set(const QImage& image) {
|
||||||
memcpy(_contents.data(), image.constBits(), _contents.size());
|
memcpy(_contents.data(), image.constBits(), _contents.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
HeightfieldTextureData::HeightfieldTextureData(const QByteArray& contents) :
|
HeightfieldTextureData::HeightfieldTextureData(const QByteArray& contents, const QVector<SharedObjectPointer>& textures) :
|
||||||
HeightfieldData(contents) {
|
HeightfieldData(contents),
|
||||||
|
_textures(textures) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HeightfieldTextureData::HeightfieldTextureData(Bitstream& in, int bytes) {
|
HeightfieldTextureData::HeightfieldTextureData(Bitstream& in, int bytes) {
|
||||||
|
@ -947,6 +948,7 @@ HeightfieldTextureData::HeightfieldTextureData(Bitstream& in, int bytes, const H
|
||||||
}
|
}
|
||||||
QMutexLocker locker(&reference->getEncodedDeltaMutex());
|
QMutexLocker locker(&reference->getEncodedDeltaMutex());
|
||||||
reference->setEncodedDelta(in.readAligned(bytes));
|
reference->setEncodedDelta(in.readAligned(bytes));
|
||||||
|
in.readDelta(_textures, reference->getTextures());
|
||||||
reference->setDeltaData(HeightfieldDataPointer(this));
|
reference->setDeltaData(HeightfieldDataPointer(this));
|
||||||
_contents = reference->getContents();
|
_contents = reference->getContents();
|
||||||
QImage image = decodeHeightfieldImage(reference->getEncodedDelta());
|
QImage image = decodeHeightfieldImage(reference->getEncodedDelta());
|
||||||
|
@ -978,6 +980,7 @@ void HeightfieldTextureData::write(Bitstream& out) {
|
||||||
}
|
}
|
||||||
out << _encoded.size();
|
out << _encoded.size();
|
||||||
out.writeAligned(_encoded);
|
out.writeAligned(_encoded);
|
||||||
|
out << _textures;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightfieldTextureData::writeDelta(Bitstream& out, const HeightfieldTextureDataPointer& reference) {
|
void HeightfieldTextureData::writeDelta(Bitstream& out, const HeightfieldTextureDataPointer& reference) {
|
||||||
|
@ -1023,10 +1026,12 @@ void HeightfieldTextureData::writeDelta(Bitstream& out, const HeightfieldTexture
|
||||||
}
|
}
|
||||||
out << reference->getEncodedDelta().size();
|
out << reference->getEncodedDelta().size();
|
||||||
out.writeAligned(reference->getEncodedDelta());
|
out.writeAligned(reference->getEncodedDelta());
|
||||||
|
out.writeDelta(_textures, reference->getTextures());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightfieldTextureData::read(Bitstream& in, int bytes) {
|
void HeightfieldTextureData::read(Bitstream& in, int bytes) {
|
||||||
set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)));
|
set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)));
|
||||||
|
in >> _textures;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeightfieldTextureData::set(const QImage& image) {
|
void HeightfieldTextureData::set(const QImage& image) {
|
||||||
|
@ -1363,11 +1368,8 @@ bool HeightfieldTextureAttribute::merge(void*& parent, void* children[], bool po
|
||||||
maxSize = qMax(maxSize, pointer->getContents().size());
|
maxSize = qMax(maxSize, pointer->getContents().size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (maxSize == 0) {
|
*(HeightfieldTextureDataPointer*)&parent = HeightfieldTextureDataPointer();
|
||||||
*(HeightfieldTextureDataPointer*)&parent = HeightfieldTextureDataPointer();
|
return maxSize == 0;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject,
|
SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject,
|
||||||
|
|
|
@ -527,10 +527,13 @@ typedef QExplicitlySharedDataPointer<HeightfieldTextureData> HeightfieldTextureD
|
||||||
class HeightfieldTextureData : public HeightfieldData {
|
class HeightfieldTextureData : public HeightfieldData {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HeightfieldTextureData(const QByteArray& contents);
|
HeightfieldTextureData(const QByteArray& contents,
|
||||||
|
const QVector<SharedObjectPointer>& textures = QVector<SharedObjectPointer>());
|
||||||
HeightfieldTextureData(Bitstream& in, int bytes);
|
HeightfieldTextureData(Bitstream& in, int bytes);
|
||||||
HeightfieldTextureData(Bitstream& in, int bytes, const HeightfieldTextureDataPointer& reference);
|
HeightfieldTextureData(Bitstream& in, int bytes, const HeightfieldTextureDataPointer& reference);
|
||||||
|
|
||||||
|
const QVector<SharedObjectPointer>& getTextures() const { return _textures; }
|
||||||
|
|
||||||
void write(Bitstream& out);
|
void write(Bitstream& out);
|
||||||
void writeDelta(Bitstream& out, const HeightfieldTextureDataPointer& reference);
|
void writeDelta(Bitstream& out, const HeightfieldTextureDataPointer& reference);
|
||||||
|
|
||||||
|
@ -538,6 +541,8 @@ private:
|
||||||
|
|
||||||
void read(Bitstream& in, int bytes);
|
void read(Bitstream& in, int bytes);
|
||||||
void set(const QImage& image);
|
void set(const QImage& image);
|
||||||
|
|
||||||
|
QVector<SharedObjectPointer> _textures;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Contains the description of a heightfield texture.
|
/// Contains the description of a heightfield texture.
|
||||||
|
|
|
@ -347,6 +347,8 @@ PaintHeightfieldHeightEditVisitor::PaintHeightfieldHeightEditVisitor(const Paint
|
||||||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int EIGHT_BIT_MAXIMUM = 255;
|
||||||
|
|
||||||
int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
|
int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
if (!info.getBounds().intersects(_bounds)) {
|
if (!info.getBounds().intersects(_bounds)) {
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
|
@ -375,8 +377,7 @@ int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||||
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
||||||
float squaredRadius = scaledRadius * scaledRadius;
|
float squaredRadius = scaledRadius * scaledRadius;
|
||||||
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
||||||
const int EIGHT_BIT_MAXIMUM = 255;
|
|
||||||
float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size;
|
float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||||
|
@ -528,6 +529,16 @@ PaintHeightfieldTextureEditVisitor::PaintHeightfieldTextureEditVisitor(const Pai
|
||||||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QHash<uchar, int> countIndices(const QByteArray& contents) {
|
||||||
|
QHash<uchar, int> counts;
|
||||||
|
for (const uchar* src = (const uchar*)contents.constData(), *end = src + contents.size(); src != end; src++) {
|
||||||
|
if (*src != 0) {
|
||||||
|
counts[*src]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
|
int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
if (!info.getBounds().intersects(_bounds)) {
|
if (!info.getBounds().intersects(_bounds)) {
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
|
@ -539,7 +550,47 @@ int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
if (!pointer) {
|
if (!pointer) {
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
|
QVector<SharedObjectPointer> textures = pointer->getTextures();
|
||||||
QByteArray contents(pointer->getContents());
|
QByteArray contents(pointer->getContents());
|
||||||
|
uchar textureIndex = 0;
|
||||||
|
if (_edit.texture && static_cast<HeightfieldTexture*>(_edit.texture.data())->getURL().isValid()) {
|
||||||
|
// first look for a matching existing texture, noting the first reusable slot
|
||||||
|
int firstEmptyIndex = -1;
|
||||||
|
for (int i = 0; i < textures.size(); i++) {
|
||||||
|
const SharedObjectPointer& texture = textures.at(i);
|
||||||
|
if (texture) {
|
||||||
|
if (texture->equals(_edit.texture.data())) {
|
||||||
|
textureIndex = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (firstEmptyIndex == -1) {
|
||||||
|
firstEmptyIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if nothing found, use the first empty slot or append
|
||||||
|
if (textureIndex == 0) {
|
||||||
|
if (firstEmptyIndex != -1) {
|
||||||
|
textures[firstEmptyIndex] = _edit.texture;
|
||||||
|
textureIndex = firstEmptyIndex + 1;
|
||||||
|
|
||||||
|
} else if (textures.size() < EIGHT_BIT_MAXIMUM) {
|
||||||
|
textures.append(_edit.texture);
|
||||||
|
textureIndex = textures.size();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// last resort: find the least-used texture and remove it
|
||||||
|
QHash<uchar, int> counts = countIndices(contents);
|
||||||
|
int lowestCount = INT_MAX;
|
||||||
|
for (QHash<uchar, int>::const_iterator it = counts.constBegin(); it != counts.constEnd(); it++) {
|
||||||
|
if (it.value() < lowestCount) {
|
||||||
|
textureIndex = it.key();
|
||||||
|
lowestCount = it.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contents.replace((char)textureIndex, (char)0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
int size = glm::sqrt((float)contents.size());
|
int size = glm::sqrt((float)contents.size());
|
||||||
int highest = size - 1;
|
int highest = size - 1;
|
||||||
float heightScale = size / info.size;
|
float heightScale = size / info.size;
|
||||||
|
@ -554,22 +605,33 @@ int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
|
||||||
// paint all points within the radius
|
// paint all points within the radius
|
||||||
float z = qMax(start.z, 0.0f);
|
float z = qMax(start.z, 0.0f);
|
||||||
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest);
|
||||||
char* lineDest = contents.data() + (int)z * size + (int)startX;
|
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
||||||
float squaredRadius = scaledRadius * scaledRadius;
|
float squaredRadius = scaledRadius * scaledRadius;
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
QHash<uchar, int> counts;
|
||||||
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) {
|
||||||
char* dest = lineDest;
|
uchar* dest = lineDest;
|
||||||
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
for (float x = startX; x <= endX; x += 1.0f, dest++) {
|
||||||
float dx = x - center.x, dz = z - center.z;
|
float dx = x - center.x, dz = z - center.z;
|
||||||
if (dx * dx + dz * dz <= squaredRadius) {
|
if (dx * dx + dz * dz <= squaredRadius) {
|
||||||
*dest = 1;
|
*dest = textureIndex;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lineDest += size;
|
lineDest += size;
|
||||||
}
|
}
|
||||||
if (changed) {
|
if (changed) {
|
||||||
HeightfieldTextureDataPointer newPointer(new HeightfieldTextureData(contents));
|
// clear any unused textures
|
||||||
|
QHash<uchar, int> counts = countIndices(contents);
|
||||||
|
for (int i = 0; i < textures.size(); i++) {
|
||||||
|
if (counts.value(i + 1) == 0) {
|
||||||
|
textures[i] = SharedObjectPointer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!(textures.isEmpty() || textures.last())) {
|
||||||
|
textures.removeLast();
|
||||||
|
}
|
||||||
|
HeightfieldTextureDataPointer newPointer(new HeightfieldTextureData(contents, textures));
|
||||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldTextureDataPointer>(newPointer));
|
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldTextureDataPointer>(newPointer));
|
||||||
}
|
}
|
||||||
paintColor(info, 1, _edit.position, _edit.radius, _edit.averageColor);
|
paintColor(info, 1, _edit.position, _edit.radius, _edit.averageColor);
|
||||||
|
|
Loading…
Reference in a new issue