More texture bits.

This commit is contained in:
Andrzej Kapolka 2014-08-19 17:20:14 -07:00
parent 3136e4df76
commit 540d074270
3 changed files with 83 additions and 14 deletions

View file

@ -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,

View file

@ -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.

View file

@ -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);