mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-18 01:33:44 +02:00
More voxel editing bits.
This commit is contained in:
parent
9a4d56b4e9
commit
96b4a1080c
5 changed files with 510 additions and 246 deletions
|
@ -978,14 +978,51 @@ void HeightfieldPreview::render(const glm::vec3& translation, float scale) const
|
|||
glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
VoxelBuffer::VoxelBuffer(const QVector<VoxelVertex>& vertices, const QVector<int>& indices,
|
||||
VoxelBuffer::VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>& indices,
|
||||
const QVector<SharedObjectPointer>& materials) :
|
||||
_vertices(vertices),
|
||||
_indices(indices),
|
||||
_vertexCount(vertices.size()),
|
||||
_indexCount(indices.size()),
|
||||
_indexBuffer(QOpenGLBuffer::IndexBuffer),
|
||||
_materials(materials) {
|
||||
}
|
||||
|
||||
void VoxelBuffer::render(bool cursor) {
|
||||
if (!_vertexBuffer.isCreated()) {
|
||||
_vertexBuffer.create();
|
||||
_vertexBuffer.bind();
|
||||
_vertexBuffer.allocate(_vertices.constData(), _vertices.size() * sizeof(VoxelPoint));
|
||||
_vertices.clear();
|
||||
|
||||
_indexBuffer.create();
|
||||
_indexBuffer.bind();
|
||||
_indexBuffer.allocate(_indices.constData(), _indices.size() * sizeof(int));
|
||||
_indices.clear();
|
||||
|
||||
if (!_materials.isEmpty()) {
|
||||
_networkTextures.resize(_materials.size());
|
||||
for (int i = 0; i < _materials.size(); i++) {
|
||||
const SharedObjectPointer material = _materials.at(i);
|
||||
if (material) {
|
||||
_networkTextures[i] = Application::getInstance()->getTextureCache()->getTexture(
|
||||
static_cast<MaterialObject*>(material.data())->getDiffuse(), SPLAT_TEXTURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_vertexBuffer.bind();
|
||||
_indexBuffer.bind();
|
||||
}
|
||||
VoxelPoint* point = 0;
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(VoxelPoint), &point->vertex);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelPoint), &point->color);
|
||||
glNormalPointer(GL_BYTE, sizeof(VoxelPoint), &point->normal);
|
||||
|
||||
glDrawRangeElements(GL_QUADS, 0, _vertexCount - 1, _indexCount, GL_UNSIGNED_INT, 0);
|
||||
|
||||
_vertexBuffer.release();
|
||||
_indexBuffer.release();
|
||||
}
|
||||
|
||||
BufferDataAttribute::BufferDataAttribute(const QString& name) :
|
||||
|
@ -1506,8 +1543,9 @@ public:
|
|||
|
||||
VoxelAugmentVisitor::VoxelAugmentVisitor(const MetavoxelLOD& lod) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getVoxelColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelMaterialAttribute(), QVector<AttributePointer>() <<
|
||||
Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute(), lod) {
|
||||
AttributeRegistry::getInstance()->getVoxelMaterialAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelHermiteAttribute(), QVector<AttributePointer>() <<
|
||||
Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute(), lod) {
|
||||
}
|
||||
|
||||
int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
|
||||
|
@ -1517,7 +1555,7 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
|
|||
VoxelBuffer* buffer = NULL;
|
||||
VoxelColorDataPointer color = info.inputValues.at(0).getInlineValue<VoxelColorDataPointer>();
|
||||
if (color) {
|
||||
QVector<VoxelVertex> vertices;
|
||||
QVector<VoxelPoint> vertices;
|
||||
QVector<int> indices;
|
||||
|
||||
const QVector<QRgb>& contents = color->getContents();
|
||||
|
@ -1534,7 +1572,7 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) {
|
|||
const int ALPHA_OFFSET = 24;
|
||||
const int MAX_ALPHA_TOTAL = EIGHT_BIT_MAXIMUM * 8;
|
||||
for (int z = 0; z < highest; z++) {
|
||||
for (int y = 0; y < highest; z++) {
|
||||
for (int y = 0; y < highest; y++) {
|
||||
for (int x = 0; x < highest; x++, src++) {
|
||||
int alpha0 = src[0] >> ALPHA_OFFSET;
|
||||
int alpha1 = src[1] >> ALPHA_OFFSET;
|
||||
|
|
|
@ -215,9 +215,9 @@ private:
|
|||
};
|
||||
|
||||
/// Describes contents of a vertex in a voxel buffer.
|
||||
class VoxelVertex {
|
||||
class VoxelPoint {
|
||||
public:
|
||||
glm::vec3 position;
|
||||
glm::vec3 vertex;
|
||||
quint8 color[3];
|
||||
quint8 normal[3];
|
||||
};
|
||||
|
@ -226,15 +226,19 @@ public:
|
|||
class VoxelBuffer : public BufferData {
|
||||
public:
|
||||
|
||||
VoxelBuffer(const QVector<VoxelVertex>& vertices, const QVector<int>& indices,
|
||||
VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>& indices,
|
||||
const QVector<SharedObjectPointer>& materials = QVector<SharedObjectPointer>());
|
||||
|
||||
virtual void render(bool cursor = false);
|
||||
|
||||
private:
|
||||
|
||||
QVector<VoxelVertex> _vertices;
|
||||
QVector<VoxelPoint> _vertices;
|
||||
QVector<int> _indices;
|
||||
int _vertexCount;
|
||||
int _indexCount;
|
||||
QOpenGLBuffer _vertexBuffer;
|
||||
QOpenGLBuffer _indexBuffer;
|
||||
QVector<SharedObjectPointer> _materials;
|
||||
QVector<NetworkTexturePointer> _networkTextures;
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@ REGISTER_META_OBJECT(SharedObjectAttribute)
|
|||
REGISTER_META_OBJECT(SharedObjectSetAttribute)
|
||||
REGISTER_META_OBJECT(SpannerSetAttribute)
|
||||
REGISTER_META_OBJECT(VoxelColorAttribute)
|
||||
REGISTER_META_OBJECT(VoxelHermiteAttribute)
|
||||
REGISTER_META_OBJECT(VoxelMaterialAttribute)
|
||||
|
||||
static int attributePointerMetaTypeId = qRegisterMetaType<AttributePointer>();
|
||||
|
@ -56,7 +57,8 @@ AttributeRegistry::AttributeRegistry() :
|
|||
_heightfieldColorAttribute(registerAttribute(new HeightfieldColorAttribute("heightfieldColor"))),
|
||||
_heightfieldMaterialAttribute(registerAttribute(new HeightfieldMaterialAttribute("heightfieldMaterial"))),
|
||||
_voxelColorAttribute(registerAttribute(new VoxelColorAttribute("voxelColor"))),
|
||||
_voxelMaterialAttribute(registerAttribute(new VoxelMaterialAttribute("voxelMaterial"))) {
|
||||
_voxelMaterialAttribute(registerAttribute(new VoxelMaterialAttribute("voxelMaterial"))),
|
||||
_voxelHermiteAttribute(registerAttribute(new VoxelHermiteAttribute("voxelHermite"))) {
|
||||
|
||||
// our baseline LOD threshold is for voxels; spanners and heightfields are a different story
|
||||
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f;
|
||||
|
@ -72,6 +74,7 @@ AttributeRegistry::AttributeRegistry() :
|
|||
_voxelColorAttribute->setLODThresholdMultiplier(VOXEL_LOD_THRESHOLD_MULTIPLIER);
|
||||
_voxelColorAttribute->setUserFacing(true);
|
||||
_voxelMaterialAttribute->setLODThresholdMultiplier(VOXEL_LOD_THRESHOLD_MULTIPLIER);
|
||||
_voxelHermiteAttribute->setLODThresholdMultiplier(VOXEL_LOD_THRESHOLD_MULTIPLIER);
|
||||
}
|
||||
|
||||
static QScriptValue qDebugFunction(QScriptContext* context, QScriptEngine* engine) {
|
||||
|
@ -1829,6 +1832,194 @@ bool VoxelMaterialAttribute::merge(void*& parent, void* children[], bool postRea
|
|||
return maxSize == 0;
|
||||
}
|
||||
|
||||
VoxelHermiteData::VoxelHermiteData(const QVector<QRgb>& contents, int size) :
|
||||
_contents(contents),
|
||||
_size(size) {
|
||||
}
|
||||
|
||||
VoxelHermiteData::VoxelHermiteData(Bitstream& in, int bytes) {
|
||||
read(in, bytes);
|
||||
}
|
||||
|
||||
VoxelHermiteData::VoxelHermiteData(Bitstream& in, int bytes, const VoxelHermiteDataPointer& reference) {
|
||||
if (!reference) {
|
||||
read(in, bytes);
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&reference->getEncodedDeltaMutex());
|
||||
reference->setEncodedDelta(in.readAligned(bytes));
|
||||
reference->setDeltaData(DataBlockPointer(this));
|
||||
_contents = reference->getContents();
|
||||
_size = reference->getSize();
|
||||
|
||||
int offsetX, offsetY, offsetZ, sizeX, sizeY, sizeZ;
|
||||
QVector<QRgb> delta = decodeVoxelColor(reference->getEncodedDelta(), offsetX, offsetY, offsetZ, sizeX, sizeY, sizeZ);
|
||||
if (delta.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (offsetX == 0) {
|
||||
_contents = delta;
|
||||
_size = sizeX;
|
||||
return;
|
||||
}
|
||||
int minX = offsetX - 1;
|
||||
int minY = offsetY - 1;
|
||||
int minZ = offsetZ - 1;
|
||||
const QRgb* src = delta.constData();
|
||||
int destStride = _size * EDGE_COUNT;
|
||||
int destStride2 = _size * destStride;
|
||||
QRgb* planeDest = _contents.data() + minZ * destStride2 + minY * destStride + minX * EDGE_COUNT;
|
||||
int srcStride = sizeX * EDGE_COUNT;
|
||||
int length = srcStride * sizeof(QRgb);
|
||||
for (int z = 0; z < sizeZ; z++, planeDest += destStride2) {
|
||||
QRgb* dest = planeDest;
|
||||
for (int y = 0; y < sizeY; y++, src += srcStride, dest += destStride) {
|
||||
memcpy(dest, src, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelHermiteData::write(Bitstream& out) {
|
||||
QMutexLocker locker(&_encodedMutex);
|
||||
if (_encoded.isEmpty()) {
|
||||
_encoded = encodeVoxelColor(0, 0, 0, _size, _size, _size, _contents);
|
||||
}
|
||||
out << _encoded.size();
|
||||
out.writeAligned(_encoded);
|
||||
}
|
||||
|
||||
void VoxelHermiteData::writeDelta(Bitstream& out, const VoxelHermiteDataPointer& reference) {
|
||||
if (!reference || reference->getSize() != _size) {
|
||||
write(out);
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&reference->getEncodedDeltaMutex());
|
||||
if (reference->getEncodedDelta().isEmpty() || reference->getDeltaData() != this) {
|
||||
int minX = _size, minY = _size, minZ = _size;
|
||||
int maxX = -1, maxY = -1, maxZ = -1;
|
||||
const QRgb* src = _contents.constData();
|
||||
const QRgb* ref = reference->getContents().constData();
|
||||
for (int z = 0; z < _size; z++) {
|
||||
bool differenceZ = false;
|
||||
for (int y = 0; y < _size; y++) {
|
||||
bool differenceY = false;
|
||||
for (int x = 0; x < _size; x++) {
|
||||
if (*src++ != *ref++ || *src++ != *ref++ || *src++ != *ref++) {
|
||||
minX = qMin(minX, x);
|
||||
maxX = qMax(maxX, x);
|
||||
differenceY = differenceZ = true;
|
||||
}
|
||||
}
|
||||
if (differenceY) {
|
||||
minY = qMin(minY, y);
|
||||
maxY = qMax(maxY, y);
|
||||
}
|
||||
}
|
||||
if (differenceZ) {
|
||||
minZ = qMin(minZ, z);
|
||||
maxZ = qMax(maxZ, z);
|
||||
}
|
||||
}
|
||||
QVector<QRgb> delta;
|
||||
int sizeX = 0, sizeY = 0, sizeZ = 0;
|
||||
if (maxX >= minX) {
|
||||
sizeX = maxX - minX + 1;
|
||||
sizeY = maxY - minY + 1;
|
||||
sizeZ = maxZ - minZ + 1;
|
||||
delta = QVector<QRgb>(sizeX * sizeY * sizeZ, 0);
|
||||
QRgb* dest = delta.data();
|
||||
int srcStride = _size * EDGE_COUNT;
|
||||
int srcStride2 = _size * srcStride;
|
||||
const QRgb* planeSrc = _contents.constData() + minZ * srcStride2 + minY * srcStride + minX * EDGE_COUNT;
|
||||
int destStride = sizeX * EDGE_COUNT;
|
||||
int length = destStride * sizeof(QRgb);
|
||||
for (int z = 0; z < sizeZ; z++, planeSrc += srcStride2) {
|
||||
src = planeSrc;
|
||||
for (int y = 0; y < sizeY; y++, src += srcStride, dest += destStride) {
|
||||
memcpy(dest, src, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
reference->setEncodedDelta(encodeVoxelColor(minX + 1, minY + 1, minZ + 1, sizeX, sizeY, sizeZ, delta));
|
||||
reference->setDeltaData(DataBlockPointer(this));
|
||||
}
|
||||
out << reference->getEncodedDelta().size();
|
||||
out.writeAligned(reference->getEncodedDelta());
|
||||
}
|
||||
|
||||
void VoxelHermiteData::read(Bitstream& in, int bytes) {
|
||||
int offsetX, offsetY, offsetZ, sizeX, sizeY, sizeZ;
|
||||
_contents = decodeVoxelColor(_encoded = in.readAligned(bytes), offsetX, offsetY, offsetZ, sizeX, sizeY, sizeZ);
|
||||
_size = sizeX;
|
||||
}
|
||||
|
||||
VoxelHermiteAttribute::VoxelHermiteAttribute(const QString& name) :
|
||||
InlineAttribute<VoxelHermiteDataPointer>(name) {
|
||||
}
|
||||
|
||||
void VoxelHermiteAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(VoxelHermiteDataPointer*)&value = VoxelHermiteDataPointer();
|
||||
} else {
|
||||
*(VoxelHermiteDataPointer*)&value = VoxelHermiteDataPointer(new VoxelHermiteData(in, size));
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelHermiteAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
VoxelHermiteDataPointer data = decodeInline<VoxelHermiteDataPointer>(value);
|
||||
if (data) {
|
||||
data->write(out);
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelHermiteAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
in >> size;
|
||||
if (size == 0) {
|
||||
*(VoxelHermiteDataPointer*)&value = VoxelHermiteDataPointer();
|
||||
} else {
|
||||
*(VoxelHermiteDataPointer*)&value = VoxelHermiteDataPointer(new VoxelHermiteData(
|
||||
in, size, decodeInline<VoxelHermiteDataPointer>(reference)));
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelHermiteAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const {
|
||||
if (!isLeaf) {
|
||||
return;
|
||||
}
|
||||
VoxelHermiteDataPointer data = decodeInline<VoxelHermiteDataPointer>(value);
|
||||
if (data) {
|
||||
data->writeDelta(out, decodeInline<VoxelHermiteDataPointer>(reference));
|
||||
} else {
|
||||
out << 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool VoxelHermiteAttribute::merge(void*& parent, void* children[], bool postRead) const {
|
||||
int maxSize = 0;
|
||||
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||
VoxelHermiteDataPointer pointer = decodeInline<VoxelHermiteDataPointer>(children[i]);
|
||||
if (pointer) {
|
||||
maxSize = qMax(maxSize, pointer->getSize());
|
||||
}
|
||||
}
|
||||
*(VoxelHermiteDataPointer*)&parent = VoxelHermiteDataPointer();
|
||||
return maxSize == 0;
|
||||
}
|
||||
|
||||
SharedObjectAttribute::SharedObjectAttribute(const QString& name, const QMetaObject* metaObject,
|
||||
const SharedObjectPointer& defaultValue) :
|
||||
InlineAttribute<SharedObjectPointer>(name, defaultValue),
|
||||
|
|
|
@ -38,6 +38,7 @@ class MetavoxelLOD;
|
|||
class MetavoxelNode;
|
||||
class MetavoxelStreamState;
|
||||
class VoxelColorData;
|
||||
class VoxelHermiteData;
|
||||
class VoxelMaterialData;
|
||||
|
||||
typedef SharedObjectPointerTemplate<Attribute> AttributePointer;
|
||||
|
@ -117,6 +118,9 @@ public:
|
|||
/// Returns a reference to the standard VoxelMaterialDataPointer "voxelMaterial" attribute.
|
||||
const AttributePointer& getVoxelMaterialAttribute() const { return _voxelMaterialAttribute; }
|
||||
|
||||
/// Returns a reference to the standard VoxelHermiteDataPointer "voxelHermite" attribute.
|
||||
const AttributePointer& getVoxelHermiteAttribute() const { return _voxelHermiteAttribute; }
|
||||
|
||||
private:
|
||||
|
||||
static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine);
|
||||
|
@ -137,6 +141,7 @@ private:
|
|||
AttributePointer _heightfieldMaterialAttribute;
|
||||
AttributePointer _voxelColorAttribute;
|
||||
AttributePointer _voxelMaterialAttribute;
|
||||
AttributePointer _voxelHermiteAttribute;
|
||||
};
|
||||
|
||||
/// Converts a value to a void pointer.
|
||||
|
@ -728,6 +733,50 @@ public:
|
|||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
typedef QExplicitlySharedDataPointer<VoxelHermiteData> VoxelHermiteDataPointer;
|
||||
|
||||
/// Contains a block of voxel Hermite data (positions and normals at edge crossings).
|
||||
class VoxelHermiteData : public DataBlock {
|
||||
public:
|
||||
|
||||
static const int EDGE_COUNT = 3;
|
||||
|
||||
VoxelHermiteData(const QVector<QRgb>& contents, int size);
|
||||
VoxelHermiteData(Bitstream& in, int bytes);
|
||||
VoxelHermiteData(Bitstream& in, int bytes, const VoxelHermiteDataPointer& reference);
|
||||
|
||||
const QVector<QRgb>& getContents() const { return _contents; }
|
||||
|
||||
int getSize() const { return _size; }
|
||||
|
||||
void write(Bitstream& out);
|
||||
void writeDelta(Bitstream& out, const VoxelHermiteDataPointer& reference);
|
||||
|
||||
private:
|
||||
|
||||
void read(Bitstream& in, int bytes);
|
||||
|
||||
QVector<QRgb> _contents;
|
||||
int _size;
|
||||
};
|
||||
|
||||
/// An attribute that stores voxel Hermite data.
|
||||
class VoxelHermiteAttribute : public InlineAttribute<VoxelHermiteDataPointer> {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE VoxelHermiteAttribute(const QString& name = QString());
|
||||
|
||||
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
|
||||
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
|
||||
|
||||
virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const;
|
||||
virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const;
|
||||
|
||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||
};
|
||||
|
||||
/// An attribute that takes the form of QObjects of a given meta-type (a subclass of SharedObject).
|
||||
class SharedObjectAttribute : public InlineAttribute<SharedObjectPointer> {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -414,119 +414,36 @@ PaintHeightfieldColorEdit::PaintHeightfieldColorEdit(const glm::vec3& position,
|
|||
color(color) {
|
||||
}
|
||||
|
||||
class PaintHeightfieldColorEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
PaintHeightfieldColorEdit _edit;
|
||||
Box _bounds;
|
||||
};
|
||||
|
||||
PaintHeightfieldColorEditVisitor::PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute(),
|
||||
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute()),
|
||||
_edit(edit) {
|
||||
|
||||
glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
|
||||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
QByteArray contents(pointer->getContents());
|
||||
int size = glm::sqrt((float)contents.size() / DataBlock::COLOR_BYTES);
|
||||
int highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
||||
glm::vec3 center = (position - info.minimum) * heightScale;
|
||||
float scaledRadius = radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// 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 * DataBlock::COLOR_BYTES;
|
||||
char* lineDest = contents.data() + (int)z * stride + (int)startX * DataBlock::COLOR_BYTES;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
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 += DataBlock::COLOR_BYTES) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
dest[0] = red;
|
||||
dest[1] = green;
|
||||
dest[2] = blue;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
lineDest += stride;
|
||||
}
|
||||
if (changed) {
|
||||
HeightfieldColorDataPointer newPointer(new HeightfieldColorData(contents));
|
||||
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;
|
||||
}
|
||||
|
||||
void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldColorEditVisitor visitor(*this);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
position(position),
|
||||
radius(radius),
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
}
|
||||
|
||||
class PaintHeightfieldMaterialEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
PaintHeightfieldMaterialEditVisitor(const PaintHeightfieldMaterialEdit& edit);
|
||||
PaintHeightfieldMaterialEditVisitor(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& color);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
PaintHeightfieldMaterialEdit _edit;
|
||||
glm::vec3 _position;
|
||||
float _radius;
|
||||
SharedObjectPointer _material;
|
||||
QColor _color;
|
||||
Box _bounds;
|
||||
};
|
||||
|
||||
PaintHeightfieldMaterialEditVisitor::PaintHeightfieldMaterialEditVisitor(const PaintHeightfieldMaterialEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute()),
|
||||
_edit(edit) {
|
||||
PaintHeightfieldMaterialEditVisitor::PaintHeightfieldMaterialEditVisitor(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& color) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute(), QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getHeightfieldMaterialAttribute()),
|
||||
_position(position),
|
||||
_radius(radius),
|
||||
_material(material),
|
||||
_color(color) {
|
||||
|
||||
glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius);
|
||||
_bounds = Box(_edit.position - extents, _edit.position + extents);
|
||||
glm::vec3 extents(_radius, _radius, _radius);
|
||||
_bounds = Box(_position - extents, _position + extents);
|
||||
}
|
||||
|
||||
static QHash<uchar, int> countIndices(const QByteArray& contents) {
|
||||
|
@ -546,100 +463,153 @@ int PaintHeightfieldMaterialEditVisitor::visit(MetavoxelInfo& info) {
|
|||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
HeightfieldMaterialDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldMaterialDataPointer>();
|
||||
if (!pointer) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
QVector<SharedObjectPointer> materials = pointer->getMaterials();
|
||||
QByteArray contents(pointer->getContents());
|
||||
uchar materialIndex = 0;
|
||||
if (_edit.material && static_cast<MaterialObject*>(_edit.material.data())->getDiffuse().isValid()) {
|
||||
// first look for a matching existing material, noting the first reusable slot
|
||||
int firstEmptyIndex = -1;
|
||||
for (int i = 0; i < materials.size(); i++) {
|
||||
const SharedObjectPointer& material = materials.at(i);
|
||||
if (material) {
|
||||
if (material->equals(_edit.material.data())) {
|
||||
materialIndex = i + 1;
|
||||
break;
|
||||
HeightfieldColorDataPointer colorPointer = info.inputValues.at(0).getInlineValue<HeightfieldColorDataPointer>();
|
||||
if (colorPointer) {
|
||||
QByteArray contents(colorPointer->getContents());
|
||||
int size = glm::sqrt((float)contents.size() / DataBlock::COLOR_BYTES);
|
||||
int highest = size - 1;
|
||||
float heightScale = size / info.size;
|
||||
|
||||
glm::vec3 center = (_position - info.minimum) * heightScale;
|
||||
float scaledRadius = _radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// 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 * DataBlock::COLOR_BYTES;
|
||||
char* lineDest = contents.data() + (int)z * stride + (int)startX * DataBlock::COLOR_BYTES;
|
||||
float squaredRadius = scaledRadius * scaledRadius;
|
||||
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 += DataBlock::COLOR_BYTES) {
|
||||
float dx = x - center.x, dz = z - center.z;
|
||||
if (dx * dx + dz * dz <= squaredRadius) {
|
||||
dest[0] = red;
|
||||
dest[1] = green;
|
||||
dest[2] = blue;
|
||||
changed = true;
|
||||
}
|
||||
} else if (firstEmptyIndex == -1) {
|
||||
firstEmptyIndex = i;
|
||||
}
|
||||
lineDest += stride;
|
||||
}
|
||||
// if nothing found, use the first empty slot or append
|
||||
if (materialIndex == 0) {
|
||||
if (firstEmptyIndex != -1) {
|
||||
materials[firstEmptyIndex] = _edit.material;
|
||||
materialIndex = firstEmptyIndex + 1;
|
||||
|
||||
} else if (materials.size() < EIGHT_BIT_MAXIMUM) {
|
||||
materials.append(_edit.material);
|
||||
materialIndex = materials.size();
|
||||
|
||||
} else {
|
||||
// last resort: find the least-used material 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) {
|
||||
materialIndex = it.key();
|
||||
lowestCount = it.value();
|
||||
if (changed) {
|
||||
HeightfieldColorDataPointer newPointer(new HeightfieldColorData(contents));
|
||||
info.outputValues[0] = AttributeValue(info.inputValues.at(0).getAttribute(),
|
||||
encodeInline<HeightfieldColorDataPointer>(newPointer));
|
||||
}
|
||||
}
|
||||
|
||||
HeightfieldMaterialDataPointer materialPointer = info.inputValues.at(1).getInlineValue<HeightfieldMaterialDataPointer>();
|
||||
if (materialPointer) {
|
||||
QVector<SharedObjectPointer> materials = materialPointer->getMaterials();
|
||||
QByteArray contents(materialPointer->getContents());
|
||||
uchar materialIndex = 0;
|
||||
if (_material && static_cast<MaterialObject*>(_material.data())->getDiffuse().isValid()) {
|
||||
// first look for a matching existing material, noting the first reusable slot
|
||||
int firstEmptyIndex = -1;
|
||||
for (int i = 0; i < materials.size(); i++) {
|
||||
const SharedObjectPointer& material = materials.at(i);
|
||||
if (material) {
|
||||
if (material->equals(_material.data())) {
|
||||
materialIndex = i + 1;
|
||||
break;
|
||||
}
|
||||
} else if (firstEmptyIndex == -1) {
|
||||
firstEmptyIndex = i;
|
||||
}
|
||||
}
|
||||
// if nothing found, use the first empty slot or append
|
||||
if (materialIndex == 0) {
|
||||
if (firstEmptyIndex != -1) {
|
||||
materials[firstEmptyIndex] = _material;
|
||||
materialIndex = firstEmptyIndex + 1;
|
||||
|
||||
} else if (materials.size() < EIGHT_BIT_MAXIMUM) {
|
||||
materials.append(_material);
|
||||
materialIndex = materials.size();
|
||||
|
||||
} else {
|
||||
// last resort: find the least-used material 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) {
|
||||
materialIndex = it.key();
|
||||
lowestCount = it.value();
|
||||
}
|
||||
}
|
||||
contents.replace((char)materialIndex, (char)0);
|
||||
}
|
||||
contents.replace((char)materialIndex, (char)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
int size = glm::sqrt((float)contents.size());
|
||||
int highest = size - 1;
|
||||
float heightScale = highest / info.size;
|
||||
|
||||
glm::vec3 center = (_edit.position - info.minimum) * heightScale;
|
||||
float scaledRadius = _edit.radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// 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);
|
||||
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) {
|
||||
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 = materialIndex;
|
||||
changed = true;
|
||||
int size = glm::sqrt((float)contents.size());
|
||||
int highest = size - 1;
|
||||
float heightScale = highest / info.size;
|
||||
|
||||
glm::vec3 center = (_position - info.minimum) * heightScale;
|
||||
float scaledRadius = _radius * heightScale;
|
||||
glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius);
|
||||
|
||||
glm::vec3 start = glm::floor(center - extents);
|
||||
glm::vec3 end = glm::ceil(center + extents);
|
||||
|
||||
// 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);
|
||||
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) {
|
||||
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 = materialIndex;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
lineDest += size;
|
||||
}
|
||||
lineDest += size;
|
||||
}
|
||||
if (changed) {
|
||||
// clear any unused materials
|
||||
QHash<uchar, int> counts = countIndices(contents);
|
||||
for (int i = 0; i < materials.size(); i++) {
|
||||
if (counts.value(i + 1) == 0) {
|
||||
materials[i] = SharedObjectPointer();
|
||||
if (changed) {
|
||||
// clear any unused materials
|
||||
QHash<uchar, int> counts = countIndices(contents);
|
||||
for (int i = 0; i < materials.size(); i++) {
|
||||
if (counts.value(i + 1) == 0) {
|
||||
materials[i] = SharedObjectPointer();
|
||||
}
|
||||
}
|
||||
while (!(materials.isEmpty() || materials.last())) {
|
||||
materials.removeLast();
|
||||
}
|
||||
HeightfieldMaterialDataPointer newPointer(new HeightfieldMaterialData(contents, materials));
|
||||
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<HeightfieldMaterialDataPointer>(newPointer));
|
||||
}
|
||||
while (!(materials.isEmpty() || materials.last())) {
|
||||
materials.removeLast();
|
||||
}
|
||||
HeightfieldMaterialDataPointer newPointer(new HeightfieldMaterialData(contents, materials));
|
||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldMaterialDataPointer>(newPointer));
|
||||
}
|
||||
paintColor(info, 1, _edit.position, _edit.radius, _edit.averageColor);
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldMaterialEditVisitor visitor(position, radius, SharedObjectPointer(), color);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& position, float radius,
|
||||
const SharedObjectPointer& material, const QColor& averageColor) :
|
||||
position(position),
|
||||
radius(radius),
|
||||
material(material),
|
||||
averageColor(averageColor) {
|
||||
}
|
||||
|
||||
void PaintHeightfieldMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
PaintHeightfieldMaterialEditVisitor visitor(*this);
|
||||
PaintHeightfieldMaterialEditVisitor visitor(position, radius, material, averageColor);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
|
@ -654,59 +624,98 @@ const int VOXEL_BLOCK_SAMPLES = VOXEL_BLOCK_SIZE + 1;
|
|||
const int VOXEL_BLOCK_AREA = VOXEL_BLOCK_SAMPLES * VOXEL_BLOCK_SAMPLES;
|
||||
const int VOXEL_BLOCK_VOLUME = VOXEL_BLOCK_AREA * VOXEL_BLOCK_SAMPLES;
|
||||
|
||||
class VoxelColorBoxEditVisitor : public MetavoxelVisitor {
|
||||
class VoxelMaterialBoxEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
VoxelColorBoxEditVisitor(const VoxelColorBoxEdit& edit);
|
||||
VoxelMaterialBoxEditVisitor(const Box& region, float granularity,
|
||||
const SharedObjectPointer& material, const QColor& color);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
const VoxelColorBoxEdit& _edit;
|
||||
Box _region;
|
||||
float _granularity;
|
||||
SharedObjectPointer _material;
|
||||
QColor _color;
|
||||
float _blockSize;
|
||||
};
|
||||
|
||||
VoxelColorBoxEditVisitor::VoxelColorBoxEditVisitor(const VoxelColorBoxEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getVoxelColorAttribute(),
|
||||
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getVoxelColorAttribute()),
|
||||
_edit(edit),
|
||||
_blockSize(edit.granularity * VOXEL_BLOCK_SIZE) {
|
||||
VoxelMaterialBoxEditVisitor::VoxelMaterialBoxEditVisitor(const Box& region, float granularity,
|
||||
const SharedObjectPointer& material, const QColor& color) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getVoxelColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelHermiteAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelMaterialAttribute(), QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getVoxelColorAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelHermiteAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelMaterialAttribute()),
|
||||
_region(region),
|
||||
_granularity(granularity),
|
||||
_material(material),
|
||||
_color(color),
|
||||
_blockSize(granularity * VOXEL_BLOCK_SIZE) {
|
||||
}
|
||||
|
||||
int VoxelColorBoxEditVisitor::visit(MetavoxelInfo& info) {
|
||||
int VoxelMaterialBoxEditVisitor::visit(MetavoxelInfo& info) {
|
||||
Box bounds = info.getBounds();
|
||||
if (!bounds.intersects(_edit.region)) {
|
||||
if (!bounds.intersects(_region)) {
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
if (!info.size > _blockSize) {
|
||||
if (info.size > _blockSize) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
VoxelColorDataPointer pointer = info.inputValues.at(0).getInlineValue<VoxelColorDataPointer>();
|
||||
QVector<QRgb> contents = (pointer && pointer->getSize() == VOXEL_BLOCK_SAMPLES) ? pointer->getContents() :
|
||||
QVector<QRgb>(VOXEL_BLOCK_VOLUME);
|
||||
VoxelColorDataPointer colorPointer = info.inputValues.at(0).getInlineValue<VoxelColorDataPointer>();
|
||||
QVector<QRgb> colorContents = (colorPointer && colorPointer->getSize() == VOXEL_BLOCK_SAMPLES) ?
|
||||
colorPointer->getContents() : QVector<QRgb>(VOXEL_BLOCK_VOLUME);
|
||||
|
||||
Box overlap = bounds.getIntersection(_edit.region);
|
||||
int minX = (overlap.minimum.x - info.minimum.x) / _edit.granularity;
|
||||
int minY = (overlap.minimum.y - info.minimum.y) / _edit.granularity;
|
||||
int minZ = (overlap.minimum.z - info.minimum.z) / _edit.granularity;
|
||||
int sizeX = (overlap.maximum.x - overlap.minimum.x) / _edit.granularity;
|
||||
int sizeY = (overlap.maximum.y - overlap.minimum.y) / _edit.granularity;
|
||||
int sizeZ = (overlap.maximum.z - overlap.minimum.z) / _edit.granularity;
|
||||
Box overlap = info.getBounds().getIntersection(_region);
|
||||
float scale = VOXEL_BLOCK_SIZE / info.size;
|
||||
int minX = glm::ceil((overlap.minimum.x - info.minimum.x) * scale);
|
||||
int minY = glm::ceil((overlap.minimum.y - info.minimum.y) * scale);
|
||||
int minZ = glm::ceil((overlap.minimum.z - info.minimum.z) * scale);
|
||||
int sizeX = (int)((overlap.maximum.x - info.minimum.x) * scale) - minX + 1;
|
||||
int sizeY = (int)((overlap.maximum.y - info.minimum.y) * scale) - minY + 1;
|
||||
int sizeZ = (int)((overlap.maximum.z - info.minimum.z) * scale) - minZ + 1;
|
||||
|
||||
QRgb color = _edit.color.rgb();
|
||||
for (QRgb* destZ = contents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
|
||||
QRgb rgb = _color.rgb();
|
||||
for (QRgb* destZ = colorContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
|
||||
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA) {
|
||||
for (QRgb* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY; destY += VOXEL_BLOCK_SAMPLES) {
|
||||
for (QRgb* destX = destY, *endX = destX + sizeX; destX != endX; destX++) {
|
||||
*destX = color;
|
||||
*destX = rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoxelColorDataPointer newPointer(new VoxelColorData(contents, VOXEL_BLOCK_SAMPLES));
|
||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<VoxelColorDataPointer>(newPointer));
|
||||
VoxelColorDataPointer newColorPointer(new VoxelColorData(colorContents, VOXEL_BLOCK_SAMPLES));
|
||||
info.outputValues[0] = AttributeValue(info.inputValues.at(0).getAttribute(),
|
||||
encodeInline<VoxelColorDataPointer>(newColorPointer));
|
||||
|
||||
VoxelHermiteDataPointer hermitePointer = info.inputValues.at(1).getInlineValue<VoxelHermiteDataPointer>();
|
||||
QVector<QRgb> hermiteContents = (hermitePointer && hermitePointer->getSize() == VOXEL_BLOCK_SAMPLES) ?
|
||||
hermitePointer->getContents() : QVector<QRgb>(VOXEL_BLOCK_VOLUME * VoxelHermiteData::EDGE_COUNT);
|
||||
|
||||
VoxelHermiteDataPointer newHermitePointer(new VoxelHermiteData(hermiteContents, VOXEL_BLOCK_SAMPLES));
|
||||
info.outputValues[1] = AttributeValue(info.inputValues.at(1).getAttribute(),
|
||||
encodeInline<VoxelHermiteDataPointer>(newHermitePointer));
|
||||
|
||||
VoxelMaterialDataPointer materialPointer = info.inputValues.at(2).getInlineValue<VoxelMaterialDataPointer>();
|
||||
QByteArray materialContents = (materialPointer && materialPointer->getSize() == VOXEL_BLOCK_SAMPLES) ?
|
||||
materialPointer->getContents() : QByteArray(VOXEL_BLOCK_VOLUME, 0);
|
||||
|
||||
char material = 0;
|
||||
for (char* destZ = materialContents.data() + minZ * VOXEL_BLOCK_AREA + minY * VOXEL_BLOCK_SAMPLES + minX,
|
||||
*endZ = destZ + sizeZ * VOXEL_BLOCK_AREA; destZ != endZ; destZ += VOXEL_BLOCK_AREA) {
|
||||
for (char* destY = destZ, *endY = destY + sizeY * VOXEL_BLOCK_SAMPLES; destY != endY; destY += VOXEL_BLOCK_SAMPLES) {
|
||||
for (char* destX = destY, *endX = destX + sizeX; destX != endX; destX++) {
|
||||
*destX = material;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoxelMaterialDataPointer newMaterialPointer(new VoxelMaterialData(materialContents, VOXEL_BLOCK_SAMPLES));
|
||||
info.outputValues[2] = AttributeValue(_inputs.at(2), encodeInline<VoxelMaterialDataPointer>(newMaterialPointer));
|
||||
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
|
@ -715,8 +724,8 @@ void VoxelColorBoxEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& o
|
|||
while (!data.getBounds().contains(region)) {
|
||||
data.expand();
|
||||
}
|
||||
VoxelColorBoxEditVisitor setVisitor(*this);
|
||||
data.guide(setVisitor);
|
||||
VoxelMaterialBoxEditVisitor visitor(region, granularity, SharedObjectPointer(), color);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
||||
VoxelMaterialBoxEdit::VoxelMaterialBoxEdit(const Box& region, float granularity,
|
||||
|
@ -727,38 +736,11 @@ VoxelMaterialBoxEdit::VoxelMaterialBoxEdit(const Box& region, float granularity,
|
|||
averageColor(averageColor) {
|
||||
}
|
||||
|
||||
class VoxelMaterialBoxEditVisitor : public MetavoxelVisitor {
|
||||
public:
|
||||
|
||||
VoxelMaterialBoxEditVisitor(const VoxelMaterialBoxEdit& edit);
|
||||
|
||||
virtual int visit(MetavoxelInfo& info);
|
||||
|
||||
private:
|
||||
|
||||
const VoxelMaterialBoxEdit& _edit;
|
||||
};
|
||||
|
||||
VoxelMaterialBoxEditVisitor::VoxelMaterialBoxEditVisitor(const VoxelMaterialBoxEdit& edit) :
|
||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getVoxelMaterialAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelColorAttribute(), QVector<AttributePointer>() <<
|
||||
AttributeRegistry::getInstance()->getVoxelMaterialAttribute() <<
|
||||
AttributeRegistry::getInstance()->getVoxelColorAttribute()),
|
||||
_edit(edit) {
|
||||
}
|
||||
|
||||
int VoxelMaterialBoxEditVisitor::visit(MetavoxelInfo& info) {
|
||||
if (!info.isLeaf) {
|
||||
return DEFAULT_ORDER;
|
||||
}
|
||||
return STOP_RECURSION;
|
||||
}
|
||||
|
||||
void VoxelMaterialBoxEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
|
||||
// expand to fit the entire edit
|
||||
while (!data.getBounds().contains(region)) {
|
||||
data.expand();
|
||||
}
|
||||
VoxelMaterialBoxEditVisitor setVisitor(*this);
|
||||
data.guide(setVisitor);
|
||||
VoxelMaterialBoxEditVisitor visitor(region, granularity, material, averageColor);
|
||||
data.guide(visitor);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue