mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 19:13:38 +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());
|
||||
}
|
||||
|
||||
HeightfieldTextureData::HeightfieldTextureData(const QByteArray& contents) :
|
||||
HeightfieldData(contents) {
|
||||
HeightfieldTextureData::HeightfieldTextureData(const QByteArray& contents, const QVector<SharedObjectPointer>& textures) :
|
||||
HeightfieldData(contents),
|
||||
_textures(textures) {
|
||||
}
|
||||
|
||||
HeightfieldTextureData::HeightfieldTextureData(Bitstream& in, int bytes) {
|
||||
|
@ -947,6 +948,7 @@ HeightfieldTextureData::HeightfieldTextureData(Bitstream& in, int bytes, const H
|
|||
}
|
||||
QMutexLocker locker(&reference->getEncodedDeltaMutex());
|
||||
reference->setEncodedDelta(in.readAligned(bytes));
|
||||
in.readDelta(_textures, reference->getTextures());
|
||||
reference->setDeltaData(HeightfieldDataPointer(this));
|
||||
_contents = reference->getContents();
|
||||
QImage image = decodeHeightfieldImage(reference->getEncodedDelta());
|
||||
|
@ -978,6 +980,7 @@ void HeightfieldTextureData::write(Bitstream& out) {
|
|||
}
|
||||
out << _encoded.size();
|
||||
out.writeAligned(_encoded);
|
||||
out << _textures;
|
||||
}
|
||||
|
||||
void HeightfieldTextureData::writeDelta(Bitstream& out, const HeightfieldTextureDataPointer& reference) {
|
||||
|
@ -1023,10 +1026,12 @@ void HeightfieldTextureData::writeDelta(Bitstream& out, const HeightfieldTexture
|
|||
}
|
||||
out << reference->getEncodedDelta().size();
|
||||
out.writeAligned(reference->getEncodedDelta());
|
||||
out.writeDelta(_textures, reference->getTextures());
|
||||
}
|
||||
|
||||
void HeightfieldTextureData::read(Bitstream& in, int bytes) {
|
||||
set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)));
|
||||
in >> _textures;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
if (maxSize == 0) {
|
||||
*(HeightfieldTextureDataPointer*)&parent = HeightfieldTextureDataPointer();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
*(HeightfieldTextureDataPointer*)&parent = HeightfieldTextureDataPointer();
|
||||
return maxSize == 0;
|
||||
}
|
||||
|
||||
SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject,
|
||||
|
|
|
@ -527,10 +527,13 @@ typedef QExplicitlySharedDataPointer<HeightfieldTextureData> HeightfieldTextureD
|
|||
class HeightfieldTextureData : public HeightfieldData {
|
||||
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, const HeightfieldTextureDataPointer& reference);
|
||||
|
||||
const QVector<SharedObjectPointer>& getTextures() const { return _textures; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const HeightfieldTextureDataPointer& reference);
|
||||
|
||||
|
@ -538,6 +541,8 @@ private:
|
|||
|
||||
void read(Bitstream& in, int bytes);
|
||||
void set(const QImage& image);
|
||||
|
||||
QVector<SharedObjectPointer> _textures;
|
||||
};
|
||||
|
||||
/// Contains the description of a heightfield texture.
|
||||
|
|
|
@ -347,6 +347,8 @@ PaintHeightfieldHeightEditVisitor::PaintHeightfieldHeightEditVisitor(const Paint
|
|||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||
}
|
||||
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
|
||||
int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.getBounds().intersects(_bounds)) {
|
||||
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);
|
||||
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
float squaredRadiusReciprocal = 1.0f / squaredRadius;
|
||||
float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size;
|
||||
bool changed = false;
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!info.getBounds().intersects(_bounds)) {
|
||||
return STOP_RECURSION;
|
||||
|
@ -539,7 +550,47 @@ int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) {
|
|||
if (!pointer) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
QVector<SharedObjectPointer> textures = pointer->getTextures();
|
||||
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 highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
@ -554,22 +605,33 @@ 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);
|
||||
char* lineDest = contents.data() + (int)z * size + (int)startX;
|
||||
uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
bool changed = false;
|
||||
QHash<uchar, int> counts;
|
||||
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++) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
*dest = 1;
|
||||
*dest = textureIndex;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
lineDest += size;
|
||||
}
|
||||
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));
|
||||
}
|
||||
paintColor(info, 1, _edit.position, _edit.radius, _edit.averageColor);
|
||||
|
|
Loading…
Reference in a new issue