Heightfield material paint bits.

This commit is contained in:
Andrzej Kapolka 2014-11-14 16:52:29 -08:00
parent 6dc4abd286
commit bba042e823
6 changed files with 172 additions and 130 deletions

View file

@ -2869,8 +2869,7 @@ void HeightfieldRenderer::render(bool cursor) {
glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().release();
@ -2946,14 +2945,14 @@ void HeightfieldRenderer::render(bool cursor) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
DefaultMetavoxelRendererImplementation::getSplatHeightfieldProgram().release();
glDisable(GL_POLYGON_OFFSET_FILL);
glDepthMask(true);
glDepthFunc(GL_LESS);
}
glActiveTexture(GL_TEXTURE0);
glDisable(GL_CULL_FACE);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

View file

@ -354,6 +354,45 @@ void MetavoxelData::replace(const AttributePointer& attribute, const Box& bounds
guide(visitor);
}
class SpannerFetchVisitor : public SpannerVisitor {
public:
SpannerFetchVisitor(const AttributePointer& attribute, const Box& bounds, QVector<SharedObjectPointer>& results);
virtual bool visit(Spanner* spanner);
virtual int visit(MetavoxelInfo& info);
private:
const Box& _bounds;
QVector<SharedObjectPointer>& _results;
};
SpannerFetchVisitor::SpannerFetchVisitor(const AttributePointer& attribute, const Box& bounds,
QVector<SharedObjectPointer>& results) :
SpannerVisitor(QVector<AttributePointer>() << attribute),
_bounds(bounds),
_results(results) {
}
bool SpannerFetchVisitor::visit(Spanner* spanner) {
if (spanner->getBounds().intersects(_bounds)) {
_results.append(spanner);
}
return true;
}
int SpannerFetchVisitor::visit(MetavoxelInfo& info) {
return info.getBounds().intersects(_bounds) ? SpannerVisitor::visit(info) : STOP_RECURSION;
}
void MetavoxelData::getIntersecting(const AttributePointer& attribute, const Box& bounds,
QVector<SharedObjectPointer>& results) {
SpannerFetchVisitor visitor(attribute, bounds, results);
guide(visitor);
}
void MetavoxelData::clear(const AttributePointer& attribute) {
MetavoxelNode* node = _roots.take(attribute);
if (node) {

View file

@ -102,6 +102,9 @@ public:
void replace(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& oldObject,
const SharedObjectPointer& newObject);
/// Retrieves all spanners that intersect the specified bounds.
void getIntersecting(const AttributePointer& attribute, const Box& bounds, QVector<SharedObjectPointer>& results);
/// Clears all data in the specified attribute layer.
void clear(const AttributePointer& attribute);

View file

@ -242,130 +242,6 @@ MaterialEdit::MaterialEdit(const SharedObjectPointer& material, const QColor& av
averageColor(averageColor) {
}
class PaintHeightfieldMaterialEditVisitor : public MetavoxelVisitor {
public:
PaintHeightfieldMaterialEditVisitor(const glm::vec3& position, float radius,
const SharedObjectPointer& material, const QColor& color);
virtual int visit(MetavoxelInfo& info);
private:
glm::vec3 _position;
float _radius;
SharedObjectPointer _material;
QColor _color;
Box _bounds;
};
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) {
const float LARGE_EXTENT = 100000.0f;
glm::vec3 extents(_radius, LARGE_EXTENT, _radius);
_bounds = Box(_position - extents, _position + extents);
}
int PaintHeightfieldMaterialEditVisitor::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_bounds)) {
return STOP_RECURSION;
}
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
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;
}
}
lineDest += stride;
}
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 = getMaterialIndex(_material, materials, contents);
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;
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;
}
if (changed) {
clearUnusedMaterials(materials, contents);
HeightfieldMaterialDataPointer newPointer(new HeightfieldMaterialData(contents, materials));
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<HeightfieldMaterialDataPointer>(newPointer));
}
}
return STOP_RECURSION;
}
PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& position, float radius,
const SharedObjectPointer& material, const QColor& averageColor) :
MaterialEdit(material, averageColor),
@ -374,8 +250,17 @@ PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& posi
}
void PaintHeightfieldMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
PaintHeightfieldMaterialEditVisitor visitor(position, radius, material, averageColor);
data.guide(visitor);
glm::vec3 extents(radius, radius, radius);
QVector<SharedObjectPointer> results;
data.getIntersecting(AttributeRegistry::getInstance()->getSpannersAttribute(),
Box(position - extents, position + extents), results);
foreach (const SharedObjectPointer& spanner, results) {
Spanner* newSpanner = static_cast<Spanner*>(spanner.data())->paint(position, radius, material, averageColor);
if (newSpanner != spanner) {
data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), spanner, newSpanner);
}
}
}
const int VOXEL_BLOCK_SIZE = 16;

View file

@ -108,6 +108,10 @@ bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& dire
return _bounds.findRayIntersection(origin, direction, distance);
}
Spanner* Spanner::paint(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& color) {
return this;
}
bool Spanner::hasOwnColors() const {
return false;
}
@ -1604,6 +1608,112 @@ bool Heightfield::findRayIntersection(const glm::vec3& origin, const glm::vec3&
return false;
}
Spanner* Heightfield::paint(const glm::vec3& position, float radius,
const SharedObjectPointer& material, const QColor& color) {
if (!_height) {
return this;
}
int heightWidth = _height->getWidth();
int heightHeight = _height->getContents().size() / heightWidth;
int baseWidth = heightWidth - HeightfieldHeight::HEIGHT_EXTENSION + HeightfieldData::SHARED_EDGE;
int baseHeight = heightHeight - HeightfieldHeight::HEIGHT_EXTENSION + HeightfieldData::SHARED_EDGE;
Heightfield* newHeightfield = static_cast<Heightfield*>(clone(true));
int colorWidth = baseWidth, colorHeight = baseHeight;
QByteArray colorContents;
if (_color) {
colorWidth = _color->getWidth();
colorHeight = _color->getContents().size() / (colorWidth * DataBlock::COLOR_BYTES);
colorContents = _color->getContents();
} else {
colorContents = QByteArray(baseWidth * baseHeight * DataBlock::COLOR_BYTES, 0xFF);
}
int materialWidth = baseWidth, materialHeight = baseHeight;
QByteArray materialContents;
QVector<SharedObjectPointer> materials;
if (_material) {
materialWidth = _material->getWidth();
materialHeight = _material->getContents().size() / materialWidth;
materialContents = _material->getContents();
materials = _material->getMaterials();
} else {
materialContents = QByteArray(baseWidth * baseHeight, 0);
}
int highestX = colorWidth - 1;
int highestZ = colorHeight - 1;
glm::vec3 inverseScale(highestX / getScale(), 1.0f, highestZ / (getScale() * _aspectZ));
glm::vec3 center = glm::inverse(getRotation()) * (position - getTranslation()) * inverseScale;
glm::vec3 extents = glm::vec3(radius, radius, radius) * inverseScale;
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)highestX);
int stride = colorWidth * DataBlock::COLOR_BYTES;
uchar* lineDest = (uchar*)colorContents.data() + (int)z * stride + (int)startX * DataBlock::COLOR_BYTES;
float squaredRadius = extents.x * extents.x;
float multiplierZ = inverseScale.x / inverseScale.z;
char red = color.red(), green = color.green(), blue = color.blue();
bool changed = false;
for (float endZ = qMin(end.z, (float)highestZ); z <= endZ; z += 1.0f) {
uchar* dest = lineDest;
for (float x = startX; x <= endX; x += 1.0f, dest += DataBlock::COLOR_BYTES) {
float dx = x - center.x, dz = (z - center.z) * multiplierZ;
if (dx * dx + dz * dz <= squaredRadius) {
dest[0] = red;
dest[1] = green;
dest[2] = blue;
changed = true;
}
}
lineDest += stride;
}
if (changed) {
newHeightfield->setColor(HeightfieldColorPointer(new HeightfieldColor(colorWidth, colorContents)));
}
highestX = materialWidth - 1;
highestZ = materialHeight - 1;
inverseScale = glm::vec3(highestX / getScale(), 1.0f, highestZ / (getScale() * _aspectZ));
center = glm::inverse(getRotation()) * (position - getTranslation()) * inverseScale;
extents = glm::vec3(radius, radius, radius) * inverseScale;
start = glm::floor(center - extents);
end = glm::ceil(center + extents);
// paint all points within the radius
z = qMax(start.z, 0.0f);
startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highestX);
lineDest = (uchar*)materialContents.data() + (int)z * materialWidth + (int)startX;
squaredRadius = extents.x * extents.x;
uchar materialIndex = getMaterialIndex(material, materials, materialContents);
changed = false;
for (float endZ = qMin(end.z, (float)highestZ); 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) * multiplierZ;
if (dx * dx + dz * dz <= squaredRadius) {
*dest = materialIndex;
changed = true;
}
}
lineDest += materialWidth;
}
if (changed) {
clearUnusedMaterials(materials, materialContents);
newHeightfield->setMaterial(HeightfieldMaterialPointer(new HeightfieldMaterial(materialWidth,
materialContents, materials)));
}
return newHeightfield;
}
QByteArray Heightfield::getRendererClassName() const {
return "HeightfieldRenderer";
}

View file

@ -64,6 +64,10 @@ public:
/// Finds the intersection between the described ray and this spanner.
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
/// Attempts to paint on the spanner.
/// \return the modified spanner, or this if no modification was performed
virtual Spanner* paint(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& color);
/// Checks whether this spanner has its own colors.
virtual bool hasOwnColors() const;
@ -511,6 +515,8 @@ public:
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
virtual Spanner* paint(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& color);
signals:
void aspectYChanged(float aspectY);