mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 18:50:00 +02:00
Alllmost ready with the big edge sharing rejiggery.
This commit is contained in:
parent
62b84edc7f
commit
05d6b628fa
5 changed files with 304 additions and 184 deletions
|
@ -37,6 +37,9 @@ void MetavoxelSystem::init() {
|
||||||
_pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer"));
|
_pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer"));
|
||||||
_heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(
|
_heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(
|
||||||
new BufferDataAttribute("heightfieldBuffer"));
|
new BufferDataAttribute("heightfieldBuffer"));
|
||||||
|
|
||||||
|
_heightfieldBufferAttribute->setLODThresholdMultiplier(
|
||||||
|
AttributeRegistry::getInstance()->getHeightfieldAttribute()->getLODThresholdMultiplier());
|
||||||
}
|
}
|
||||||
|
|
||||||
MetavoxelLOD MetavoxelSystem::getLOD() {
|
MetavoxelLOD MetavoxelSystem::getLOD() {
|
||||||
|
@ -382,7 +385,7 @@ float MetavoxelSystem::getHeightfieldHeight(const glm::vec3& location) {
|
||||||
class HeightfieldCursorRenderVisitor : public MetavoxelVisitor {
|
class HeightfieldCursorRenderVisitor : public MetavoxelVisitor {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds);
|
HeightfieldCursorRenderVisitor(const Box& bounds);
|
||||||
|
|
||||||
virtual int visit(MetavoxelInfo& info);
|
virtual int visit(MetavoxelInfo& info);
|
||||||
|
|
||||||
|
@ -391,9 +394,9 @@ private:
|
||||||
Box _bounds;
|
Box _bounds;
|
||||||
};
|
};
|
||||||
|
|
||||||
HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds) :
|
HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const Box& bounds) :
|
||||||
MetavoxelVisitor(QVector<AttributePointer>() <<
|
MetavoxelVisitor(QVector<AttributePointer>() <<
|
||||||
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>(), lod),
|
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()),
|
||||||
_bounds(bounds) {
|
_bounds(bounds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +436,7 @@ void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float r
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
glm::vec3 extents(radius, radius, radius);
|
glm::vec3 extents(radius, radius, radius);
|
||||||
HeightfieldCursorRenderVisitor visitor(getLOD(), Box(position - extents, position + extents));
|
HeightfieldCursorRenderVisitor visitor(Box(position - extents, position + extents));
|
||||||
guideToAugmented(visitor);
|
guideToAugmented(visitor);
|
||||||
|
|
||||||
DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release();
|
DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release();
|
||||||
|
@ -601,11 +604,24 @@ HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale,
|
||||||
const QByteArray& height, const QByteArray& color) :
|
const QByteArray& height, const QByteArray& color) :
|
||||||
_translation(translation),
|
_translation(translation),
|
||||||
_scale(scale),
|
_scale(scale),
|
||||||
|
_heightBounds(translation, translation + glm::vec3(scale, scale, scale)),
|
||||||
|
_colorBounds(_heightBounds),
|
||||||
_height(height),
|
_height(height),
|
||||||
_color(color),
|
_color(color),
|
||||||
_heightTextureID(0),
|
_heightTextureID(0),
|
||||||
_colorTextureID(0),
|
_colorTextureID(0),
|
||||||
_heightSize(glm::sqrt(height.size())) {
|
_heightSize(glm::sqrt(height.size())),
|
||||||
|
_heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)),
|
||||||
|
_colorSize(glm::sqrt(color.size() / HeightfieldData::COLOR_BYTES)),
|
||||||
|
_colorIncrement(scale / (_colorSize - SHARED_EDGE)) {
|
||||||
|
|
||||||
|
_heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER;
|
||||||
|
_heightBounds.minimum.z -= _heightIncrement * HEIGHT_BORDER;
|
||||||
|
_heightBounds.maximum.x += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER);
|
||||||
|
_heightBounds.maximum.z += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER);
|
||||||
|
|
||||||
|
_colorBounds.maximum.x += _colorIncrement * SHARED_EDGE;
|
||||||
|
_colorBounds.maximum.z += _colorIncrement * SHARED_EDGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
HeightfieldBuffer::~HeightfieldBuffer() {
|
HeightfieldBuffer::~HeightfieldBuffer() {
|
||||||
|
@ -807,17 +823,19 @@ BufferDataAttribute::BufferDataAttribute(const QString& name) :
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const {
|
bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const {
|
||||||
BufferDataPointer firstChild = decodeInline<BufferDataPointer>(children[0]);
|
*(BufferDataPointer*)&parent = _defaultValue;
|
||||||
for (int i = 1; i < MERGE_COUNT; i++) {
|
for (int i = 0; i < MERGE_COUNT; i++) {
|
||||||
if (firstChild != decodeInline<BufferDataPointer>(children[i])) {
|
if (decodeInline<BufferDataPointer>(children[i])) {
|
||||||
*(BufferDataPointer*)&parent = _defaultValue;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*(BufferDataPointer*)&parent = firstChild;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AttributeValue BufferDataAttribute::inherit(const AttributeValue& parentValue) const {
|
||||||
|
return AttributeValue(parentValue.getAttribute());
|
||||||
|
}
|
||||||
|
|
||||||
void DefaultMetavoxelRendererImplementation::init() {
|
void DefaultMetavoxelRendererImplementation::init() {
|
||||||
if (!_pointProgram.isLinked()) {
|
if (!_pointProgram.isLinked()) {
|
||||||
_pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert");
|
_pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert");
|
||||||
|
@ -923,206 +941,279 @@ bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class HeightfieldAugmentVisitor : public MetavoxelVisitor {
|
class HeightfieldFetchVisitor : public MetavoxelVisitor {
|
||||||
public:
|
|
||||||
|
|
||||||
HeightfieldAugmentVisitor(const MetavoxelLOD& lod);
|
|
||||||
|
|
||||||
virtual int visit(MetavoxelInfo& info);
|
|
||||||
};
|
|
||||||
|
|
||||||
HeightfieldAugmentVisitor::HeightfieldAugmentVisitor(const MetavoxelLOD& lod) :
|
|
||||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() <<
|
|
||||||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector<AttributePointer>() <<
|
|
||||||
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod) {
|
|
||||||
}
|
|
||||||
|
|
||||||
class BorderFetchVisitor : public MetavoxelVisitor {
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BorderFetchVisitor(const MetavoxelLOD& lod, HeightfieldBuffer* buffer);
|
HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections);
|
||||||
|
|
||||||
|
void init(HeightfieldBuffer* buffer) { _buffer = buffer; }
|
||||||
|
|
||||||
virtual int visit(MetavoxelInfo& info);
|
virtual int visit(MetavoxelInfo& info);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
const QVector<Box>& _intersections;
|
||||||
HeightfieldBuffer* _buffer;
|
HeightfieldBuffer* _buffer;
|
||||||
Box _expandedBounds;
|
|
||||||
int _heightSize;
|
|
||||||
float _heightExtension;
|
|
||||||
int _colorSize;
|
|
||||||
float _colorExtension;
|
|
||||||
Box _colorBounds;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BorderFetchVisitor::BorderFetchVisitor(const MetavoxelLOD& lod, HeightfieldBuffer* buffer) :
|
HeightfieldFetchVisitor::HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections) :
|
||||||
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() <<
|
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() <<
|
||||||
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector<AttributePointer>(), lod),
|
AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector<AttributePointer>(), lod),
|
||||||
_buffer(buffer),
|
_intersections(intersections) {
|
||||||
_expandedBounds(_buffer->getTranslation(), _buffer->getTranslation() +
|
|
||||||
glm::vec3(_buffer->getScale(), _buffer->getScale(), _buffer->getScale())),
|
|
||||||
_heightSize(glm::sqrt(buffer->getHeight().size())),
|
|
||||||
_heightExtension(_buffer->getScale() / (_heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)),
|
|
||||||
_colorSize(glm::sqrt(buffer->getColor().size() / HeightfieldData::COLOR_BYTES)),
|
|
||||||
_colorBounds(_expandedBounds) {
|
|
||||||
|
|
||||||
_expandedBounds.minimum.x -= _heightExtension * HeightfieldBuffer::HEIGHT_BORDER;
|
|
||||||
_expandedBounds.minimum.z -= _heightExtension * HeightfieldBuffer::HEIGHT_BORDER;
|
|
||||||
_expandedBounds.maximum.x += _heightExtension * (HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE);
|
|
||||||
_expandedBounds.maximum.z += _heightExtension * (HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE);
|
|
||||||
|
|
||||||
if (_colorSize > 0) {
|
|
||||||
_colorExtension = buffer->getScale() / (_colorSize - HeightfieldBuffer::SHARED_EDGE);
|
|
||||||
_colorBounds.maximum.x += _colorExtension * HeightfieldBuffer::SHARED_EDGE;
|
|
||||||
_colorBounds.maximum.z += _colorExtension * HeightfieldBuffer::SHARED_EDGE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int BorderFetchVisitor::visit(MetavoxelInfo& info) {
|
int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) {
|
||||||
Box bounds = info.getBounds();
|
Box bounds = info.getBounds();
|
||||||
if (!bounds.intersects(_expandedBounds)) {
|
const Box& heightBounds = _buffer->getHeightBounds();
|
||||||
|
if (!bounds.intersects(heightBounds)) {
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
if (!info.isLeaf && info.size > _buffer->getScale()) {
|
if (!info.isLeaf && info.size > _buffer->getScale()) {
|
||||||
return DEFAULT_ORDER;
|
return DEFAULT_ORDER;
|
||||||
}
|
}
|
||||||
if (_expandedBounds.contains(bounds)) {
|
|
||||||
return STOP_RECURSION; // this is the principal, which we've already filled in
|
|
||||||
}
|
|
||||||
HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
|
HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
|
||||||
if (!height) {
|
if (!height) {
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
Box intersection = bounds.getIntersection(_expandedBounds);
|
foreach (const Box& intersection, _intersections) {
|
||||||
int destX = glm::round((intersection.minimum.x - _expandedBounds.minimum.x) / _heightExtension);
|
Box overlap = intersection.getIntersection(bounds);
|
||||||
int destY = glm::round((intersection.minimum.z - _expandedBounds.minimum.z) / _heightExtension);
|
if (overlap.isEmpty()) {
|
||||||
int destWidth = glm::round((intersection.maximum.x - intersection.minimum.x) / _heightExtension);
|
continue;
|
||||||
int destHeight = glm::round((intersection.maximum.z - intersection.minimum.z) / _heightExtension);
|
}
|
||||||
char* dest = _buffer->getHeight().data() + destY * _heightSize + destX;
|
float heightIncrement = _buffer->getHeightIncrement();
|
||||||
|
int destX = (overlap.minimum.x - heightBounds.minimum.x) / heightIncrement;
|
||||||
const QByteArray& srcHeight = height->getContents();
|
int destY = (overlap.minimum.z - heightBounds.minimum.z) / heightIncrement;
|
||||||
int srcSize = glm::sqrt(srcHeight.size());
|
int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / heightIncrement);
|
||||||
float srcExtension = info.size / srcSize;
|
int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / heightIncrement);
|
||||||
|
int heightSize = _buffer->getHeightSize();
|
||||||
if (info.size == _buffer->getScale() && srcSize == (_heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) {
|
char* dest = _buffer->getHeight().data() + destY * heightSize + destX;
|
||||||
// easy case: same resolution
|
|
||||||
int srcX = glm::round((intersection.minimum.x - info.minimum.x) / srcExtension);
|
|
||||||
int srcY = glm::round((intersection.minimum.z - info.minimum.z) / srcExtension);
|
|
||||||
|
|
||||||
const char* src = srcHeight.constData() + srcY * srcSize + srcX;
|
const QByteArray& srcHeight = height->getContents();
|
||||||
for (int y = 0; y < destHeight; y++, src += srcSize, dest += _heightSize) {
|
int srcSize = glm::sqrt(srcHeight.size());
|
||||||
memcpy(dest, src, destWidth);
|
float srcIncrement = info.size / srcSize;
|
||||||
|
|
||||||
|
if (info.size == _buffer->getScale() && srcSize == (heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) {
|
||||||
|
// easy case: same resolution
|
||||||
|
int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
|
||||||
|
int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
|
||||||
|
|
||||||
|
const char* src = srcHeight.constData() + srcY * srcSize + srcX;
|
||||||
|
for (int y = 0; y < destHeight; y++, src += srcSize, dest += heightSize) {
|
||||||
|
memcpy(dest, src, destWidth);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// more difficult: different resolutions
|
||||||
|
float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
|
||||||
|
float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
|
||||||
|
float srcAdvance = heightIncrement / srcIncrement;
|
||||||
|
int shift = 0;
|
||||||
|
float size = _buffer->getScale();
|
||||||
|
while (size < info.size) {
|
||||||
|
shift++;
|
||||||
|
size *= 2.0f;
|
||||||
|
}
|
||||||
|
const int EIGHT_BIT_MAXIMUM = 255;
|
||||||
|
int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale();
|
||||||
|
for (int y = 0; y < destHeight; y++, dest += heightSize, srcY += srcAdvance) {
|
||||||
|
const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize;
|
||||||
|
float lineSrcX = srcX;
|
||||||
|
for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) {
|
||||||
|
*lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// more difficult: different resolutions
|
int colorSize = _buffer->getColorSize();
|
||||||
float srcX = (intersection.minimum.x - info.minimum.x) / srcExtension;
|
if (colorSize == 0) {
|
||||||
float srcY = (intersection.minimum.z - info.minimum.z) / srcExtension;
|
return STOP_RECURSION;
|
||||||
float srcIncrement = _heightExtension / srcExtension;
|
|
||||||
int shift = 0;
|
|
||||||
float size = _buffer->getScale();
|
|
||||||
while (size < info.size) {
|
|
||||||
shift++;
|
|
||||||
size *= 2.0f;
|
|
||||||
}
|
}
|
||||||
const int EIGHT_BIT_MAXIMUM = 255;
|
HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();
|
||||||
int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale();
|
if (!color) {
|
||||||
for (int y = 0; y < destHeight; y++, dest += _heightSize, srcY += srcIncrement) {
|
return STOP_RECURSION;
|
||||||
const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize;
|
}
|
||||||
float lineSrcX = srcX;
|
const Box& colorBounds = _buffer->getColorBounds();
|
||||||
for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcIncrement) {
|
overlap = colorBounds.getIntersection(overlap);
|
||||||
*lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM);
|
float colorIncrement = _buffer->getColorIncrement();
|
||||||
|
destX = (overlap.minimum.x - colorBounds.minimum.x) / colorIncrement;
|
||||||
|
destY = (overlap.minimum.z - colorBounds.minimum.z) / colorIncrement;
|
||||||
|
destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / colorIncrement);
|
||||||
|
destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / colorIncrement);
|
||||||
|
dest = _buffer->getColor().data() + (destY * colorSize + destX) * HeightfieldData::COLOR_BYTES;
|
||||||
|
int destStride = colorSize * HeightfieldData::COLOR_BYTES;
|
||||||
|
int destBytes = destWidth * HeightfieldData::COLOR_BYTES;
|
||||||
|
|
||||||
|
const QByteArray& srcColor = color->getContents();
|
||||||
|
srcSize = glm::sqrt(srcColor.size() / HeightfieldData::COLOR_BYTES);
|
||||||
|
int srcStride = srcSize * HeightfieldData::COLOR_BYTES;
|
||||||
|
srcIncrement = info.size / srcSize;
|
||||||
|
|
||||||
|
if (srcIncrement == colorIncrement) {
|
||||||
|
// easy case: same resolution
|
||||||
|
int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
|
||||||
|
int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
|
||||||
|
|
||||||
|
const char* src = srcColor.constData() + (srcY * srcSize + srcX) * HeightfieldData::COLOR_BYTES;
|
||||||
|
for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) {
|
||||||
|
memcpy(dest, src, destBytes);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// more difficult: different resolutions
|
||||||
|
float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement;
|
||||||
|
float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement;
|
||||||
|
float srcAdvance = colorIncrement / srcIncrement;
|
||||||
|
for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcAdvance) {
|
||||||
|
const char* src = srcColor.constData() + (int)srcY * srcStride;
|
||||||
|
float lineSrcX = srcX;
|
||||||
|
for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += HeightfieldData::COLOR_BYTES,
|
||||||
|
lineSrcX += srcAdvance) {
|
||||||
|
const char* lineSrc = src + (int)lineSrcX * HeightfieldData::COLOR_BYTES;
|
||||||
|
lineDest[0] = lineSrc[0];
|
||||||
|
lineDest[1] = lineSrc[1];
|
||||||
|
lineDest[2] = lineSrc[2];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_colorSize == 0) {
|
|
||||||
return STOP_RECURSION;
|
|
||||||
}
|
|
||||||
HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();
|
|
||||||
if (!color) {
|
|
||||||
return STOP_RECURSION;
|
|
||||||
}
|
|
||||||
intersection = bounds.getIntersection(_colorBounds);
|
|
||||||
destX = glm::round((intersection.minimum.x - _colorBounds.minimum.x) / _colorExtension);
|
|
||||||
destY = glm::round((intersection.minimum.z - _colorBounds.minimum.z) / _colorExtension);
|
|
||||||
destWidth = glm::round((intersection.maximum.x - intersection.minimum.x) / _colorExtension);
|
|
||||||
destHeight = glm::round((intersection.maximum.z - intersection.minimum.z) / _colorExtension);
|
|
||||||
dest = _buffer->getColor().data() + (destY * _colorSize + destX) * HeightfieldData::COLOR_BYTES;
|
|
||||||
int destStride = _colorSize * HeightfieldData::COLOR_BYTES;
|
|
||||||
int destBytes = destWidth * HeightfieldData::COLOR_BYTES;
|
|
||||||
|
|
||||||
const QByteArray& srcColor = color->getContents();
|
|
||||||
srcSize = glm::sqrt(srcColor.size() / HeightfieldData::COLOR_BYTES);
|
|
||||||
int srcStride = srcSize * HeightfieldData::COLOR_BYTES;
|
|
||||||
srcExtension = info.size / srcSize;
|
|
||||||
|
|
||||||
if (srcExtension == _colorExtension) {
|
|
||||||
// easy case: same resolution
|
|
||||||
int srcX = glm::round((intersection.minimum.x - info.minimum.x) / srcExtension);
|
|
||||||
int srcY = glm::round((intersection.minimum.z - info.minimum.z) / srcExtension);
|
|
||||||
|
|
||||||
const char* src = srcColor.constData() + (srcY * srcSize + srcX) * HeightfieldData::COLOR_BYTES;
|
|
||||||
for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) {
|
|
||||||
memcpy(dest, src, destBytes);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// more difficult: different resolutions
|
|
||||||
float srcX = (intersection.minimum.x - info.minimum.x) / srcExtension;
|
|
||||||
float srcY = (intersection.minimum.z - info.minimum.z) / srcExtension;
|
|
||||||
float srcIncrement = _colorExtension / srcExtension;
|
|
||||||
for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcIncrement) {
|
|
||||||
const char* src = srcColor.constData() + (int)srcY * srcStride;
|
|
||||||
float lineSrcX = srcX;
|
|
||||||
for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += HeightfieldData::COLOR_BYTES,
|
|
||||||
lineSrcX += srcIncrement) {
|
|
||||||
const char* lineSrc = src + (int)lineSrcX * HeightfieldData::COLOR_BYTES;
|
|
||||||
lineDest[0] = lineSrc[0];
|
|
||||||
lineDest[1] = lineSrc[1];
|
|
||||||
lineDest[2] = lineSrc[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) {
|
class HeightfieldRegionVisitor : public MetavoxelVisitor {
|
||||||
if (info.isLeaf) {
|
public:
|
||||||
HeightfieldBuffer* buffer = NULL;
|
|
||||||
HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
|
QVector<Box> regions;
|
||||||
if (height) {
|
Box regionBounds;
|
||||||
const QByteArray& heightContents = height->getContents();
|
|
||||||
int size = glm::sqrt(heightContents.size());
|
HeightfieldRegionVisitor(const MetavoxelLOD& lod);
|
||||||
int extendedSize = size + HeightfieldBuffer::HEIGHT_EXTENSION;
|
|
||||||
QByteArray extendedHeightContents(extendedSize * extendedSize, 0);
|
virtual int visit(MetavoxelInfo& info);
|
||||||
char* dest = extendedHeightContents.data() + (extendedSize + 1) * HeightfieldBuffer::HEIGHT_BORDER;
|
|
||||||
const char* src = heightContents.constData();
|
private:
|
||||||
for (int z = 0; z < size; z++, src += size, dest += extendedSize) {
|
|
||||||
memcpy(dest, src, size);
|
void addRegion(const Box& unextended, const Box& extended);
|
||||||
}
|
|
||||||
QByteArray extendedColorContents;
|
QVector<Box> _intersections;
|
||||||
HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();
|
HeightfieldFetchVisitor _fetchVisitor;
|
||||||
if (color) {
|
};
|
||||||
const QByteArray& colorContents = color->getContents();
|
|
||||||
int colorSize = glm::sqrt(colorContents.size() / HeightfieldData::COLOR_BYTES);
|
HeightfieldRegionVisitor::HeightfieldRegionVisitor(const MetavoxelLOD& lod) :
|
||||||
int extendedColorSize = colorSize + HeightfieldBuffer::SHARED_EDGE;
|
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() <<
|
||||||
extendedColorContents = QByteArray(extendedColorSize * extendedColorSize * HeightfieldData::COLOR_BYTES, 0);
|
AttributeRegistry::getInstance()->getHeightfieldColorAttribute() <<
|
||||||
char* dest = extendedColorContents.data();
|
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() <<
|
||||||
const char* src = colorContents.constData();
|
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod),
|
||||||
int srcStride = colorSize * HeightfieldData::COLOR_BYTES;
|
regionBounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)),
|
||||||
int destStride = extendedColorSize * HeightfieldData::COLOR_BYTES;
|
_fetchVisitor(lod, _intersections) {
|
||||||
for (int z = 0; z < colorSize; z++, src += srcStride, dest += destStride) {
|
}
|
||||||
memcpy(dest, src, srcStride);
|
|
||||||
}
|
int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) {
|
||||||
}
|
if (!info.isLeaf) {
|
||||||
buffer = new HeightfieldBuffer(info.minimum, info.size, extendedHeightContents, extendedColorContents);
|
return DEFAULT_ORDER;
|
||||||
BorderFetchVisitor visitor(_lod, buffer);
|
}
|
||||||
_data->guide(visitor);
|
HeightfieldBuffer* buffer = NULL;
|
||||||
|
HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>();
|
||||||
|
if (height) {
|
||||||
|
const QByteArray& heightContents = height->getContents();
|
||||||
|
int size = glm::sqrt(heightContents.size());
|
||||||
|
int extendedSize = size + HeightfieldBuffer::HEIGHT_EXTENSION;
|
||||||
|
int heightContentsSize = extendedSize * extendedSize;
|
||||||
|
|
||||||
|
HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>();
|
||||||
|
int colorContentsSize = 0;
|
||||||
|
if (color) {
|
||||||
|
const QByteArray& colorContents = color->getContents();
|
||||||
|
int colorSize = glm::sqrt(colorContents.size() / HeightfieldData::COLOR_BYTES);
|
||||||
|
int extendedColorSize = colorSize + HeightfieldBuffer::SHARED_EDGE;
|
||||||
|
colorContentsSize = extendedColorSize * extendedColorSize * HeightfieldData::COLOR_BYTES;
|
||||||
}
|
}
|
||||||
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer)));
|
|
||||||
|
const HeightfieldBuffer* existingBuffer = static_cast<const HeightfieldBuffer*>(
|
||||||
|
info.inputValues.at(2).getInlineValue<BufferDataPointer>().data());
|
||||||
|
Box bounds = info.getBounds();
|
||||||
|
if (existingBuffer && existingBuffer->getHeight().size() == heightContentsSize &&
|
||||||
|
existingBuffer->getColor().size() == colorContentsSize) {
|
||||||
|
// we already have a buffer of the correct resolution
|
||||||
|
addRegion(bounds, existingBuffer->getHeightBounds());
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
// we must create a new buffer and update its borders
|
||||||
|
buffer = new HeightfieldBuffer(info.minimum, info.size, QByteArray(heightContentsSize, 0),
|
||||||
|
QByteArray(colorContentsSize, 0));
|
||||||
|
const Box& heightBounds = buffer->getHeightBounds();
|
||||||
|
addRegion(bounds, heightBounds);
|
||||||
|
|
||||||
|
_intersections.clear();
|
||||||
|
_intersections.append(Box(heightBounds.minimum,
|
||||||
|
glm::vec3(bounds.maximum.x, heightBounds.maximum.y, bounds.minimum.z)));
|
||||||
|
_intersections.append(Box(glm::vec3(bounds.maximum.x, heightBounds.minimum.y, heightBounds.minimum.z),
|
||||||
|
glm::vec3(heightBounds.maximum.x, heightBounds.maximum.y, bounds.maximum.z)));
|
||||||
|
_intersections.append(Box(glm::vec3(bounds.minimum.x, heightBounds.minimum.y, bounds.maximum.z),
|
||||||
|
heightBounds.maximum));
|
||||||
|
_intersections.append(Box(glm::vec3(heightBounds.minimum.x, heightBounds.minimum.y, bounds.minimum.z),
|
||||||
|
glm::vec3(bounds.minimum.x, heightBounds.maximum.y, heightBounds.maximum.z)));
|
||||||
|
|
||||||
|
_fetchVisitor.init(buffer);
|
||||||
|
_data->guide(_fetchVisitor);
|
||||||
|
}
|
||||||
|
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer)));
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeightfieldRegionVisitor::addRegion(const Box& unextended, const Box& extended) {
|
||||||
|
regions.append(unextended);
|
||||||
|
regionBounds.add(extended);
|
||||||
|
}
|
||||||
|
|
||||||
|
class HeightfieldUpdateVisitor : public MetavoxelVisitor {
|
||||||
|
public:
|
||||||
|
|
||||||
|
HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions, const Box& regionBounds);
|
||||||
|
|
||||||
|
virtual int visit(MetavoxelInfo& info);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const QVector<Box>& _regions;
|
||||||
|
const Box& _regionBounds;
|
||||||
|
QVector<Box> _intersections;
|
||||||
|
HeightfieldFetchVisitor _fetchVisitor;
|
||||||
|
};
|
||||||
|
|
||||||
|
HeightfieldUpdateVisitor::HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions,
|
||||||
|
const Box& regionBounds) :
|
||||||
|
MetavoxelVisitor(QVector<AttributePointer>() <<
|
||||||
|
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() <<
|
||||||
|
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod),
|
||||||
|
_regions(regions),
|
||||||
|
_regionBounds(regionBounds),
|
||||||
|
_fetchVisitor(lod, _intersections) {
|
||||||
|
}
|
||||||
|
|
||||||
|
int HeightfieldUpdateVisitor::visit(MetavoxelInfo& info) {
|
||||||
|
if (!info.getBounds().intersects(_regionBounds)) {
|
||||||
return STOP_RECURSION;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
return DEFAULT_ORDER;
|
if (!info.isLeaf) {
|
||||||
|
return DEFAULT_ORDER;
|
||||||
|
}
|
||||||
|
const HeightfieldBuffer* buffer = static_cast<const HeightfieldBuffer*>(
|
||||||
|
info.inputValues.at(0).getInlineValue<BufferDataPointer>().data());
|
||||||
|
if (!buffer) {
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
_intersections.clear();
|
||||||
|
foreach (const Box& region, _regions) {
|
||||||
|
if (region.intersects(buffer->getHeightBounds())) {
|
||||||
|
_intersections.append(region.getIntersection(buffer->getHeightBounds()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_intersections.isEmpty()) {
|
||||||
|
return STOP_RECURSION;
|
||||||
|
}
|
||||||
|
HeightfieldBuffer* newBuffer = new HeightfieldBuffer(info.minimum, info.size,
|
||||||
|
buffer->getHeight(), buffer->getColor());
|
||||||
|
_fetchVisitor.init(newBuffer);
|
||||||
|
_data->guide(_fetchVisitor);
|
||||||
|
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(newBuffer)));
|
||||||
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous,
|
void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous,
|
||||||
|
@ -1149,8 +1240,12 @@ void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const
|
||||||
PointAugmentVisitor pointAugmentVisitor(lod);
|
PointAugmentVisitor pointAugmentVisitor(lod);
|
||||||
data.guideToDifferent(expandedPrevious, pointAugmentVisitor);
|
data.guideToDifferent(expandedPrevious, pointAugmentVisitor);
|
||||||
|
|
||||||
HeightfieldAugmentVisitor heightfieldAugmentVisitor(lod);
|
HeightfieldRegionVisitor heightfieldRegionVisitor(lod);
|
||||||
data.guideToDifferent(expandedPrevious, heightfieldAugmentVisitor);
|
data.guideToDifferent(expandedPrevious, heightfieldRegionVisitor);
|
||||||
|
|
||||||
|
HeightfieldUpdateVisitor heightfieldUpdateVisitor(lod, heightfieldRegionVisitor.regions,
|
||||||
|
heightfieldRegionVisitor.regionBounds);
|
||||||
|
data.guide(heightfieldUpdateVisitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpannerSimulateVisitor : public SpannerVisitor {
|
class SpannerSimulateVisitor : public SpannerVisitor {
|
||||||
|
@ -1222,7 +1317,7 @@ bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum,
|
||||||
class BufferRenderVisitor : public MetavoxelVisitor {
|
class BufferRenderVisitor : public MetavoxelVisitor {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod);
|
BufferRenderVisitor(const AttributePointer& attribute);
|
||||||
|
|
||||||
virtual int visit(MetavoxelInfo& info);
|
virtual int visit(MetavoxelInfo& info);
|
||||||
|
|
||||||
|
@ -1232,8 +1327,8 @@ private:
|
||||||
int _containmentDepth;
|
int _containmentDepth;
|
||||||
};
|
};
|
||||||
|
|
||||||
BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod) :
|
BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) :
|
||||||
MetavoxelVisitor(QVector<AttributePointer>() << attribute, QVector<AttributePointer>(), lod),
|
MetavoxelVisitor(QVector<AttributePointer>() << attribute),
|
||||||
_order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())),
|
_order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())),
|
||||||
_containmentDepth(INT_MAX) {
|
_containmentDepth(INT_MAX) {
|
||||||
}
|
}
|
||||||
|
@ -1247,11 +1342,14 @@ int BufferRenderVisitor::visit(MetavoxelInfo& info) {
|
||||||
}
|
}
|
||||||
_containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX;
|
_containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX;
|
||||||
}
|
}
|
||||||
|
if (!info.isLeaf) {
|
||||||
|
return _order;
|
||||||
|
}
|
||||||
BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>();
|
BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>();
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
buffer->render();
|
buffer->render();
|
||||||
}
|
}
|
||||||
return info.isLeaf ? STOP_RECURSION : _order;
|
return STOP_RECURSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) {
|
void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) {
|
||||||
|
@ -1280,7 +1378,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod);
|
BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute());
|
||||||
data.guide(pointRenderVisitor);
|
data.guide(pointRenderVisitor);
|
||||||
|
|
||||||
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
|
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
|
||||||
|
@ -1300,8 +1398,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
|
||||||
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(),
|
BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute());
|
||||||
lod);
|
|
||||||
data.guide(heightfieldRenderVisitor);
|
data.guide(heightfieldRenderVisitor);
|
||||||
|
|
||||||
_heightfieldProgram.release();
|
_heightfieldProgram.release();
|
||||||
|
|
|
@ -145,6 +145,9 @@ public:
|
||||||
const glm::vec3& getTranslation() const { return _translation; }
|
const glm::vec3& getTranslation() const { return _translation; }
|
||||||
float getScale() const { return _scale; }
|
float getScale() const { return _scale; }
|
||||||
|
|
||||||
|
const Box& getHeightBounds() const { return _heightBounds; }
|
||||||
|
const Box& getColorBounds() const { return _colorBounds; }
|
||||||
|
|
||||||
QByteArray& getHeight() { return _height; }
|
QByteArray& getHeight() { return _height; }
|
||||||
const QByteArray& getHeight() const { return _height; }
|
const QByteArray& getHeight() const { return _height; }
|
||||||
|
|
||||||
|
@ -154,17 +157,28 @@ public:
|
||||||
QByteArray getUnextendedHeight() const;
|
QByteArray getUnextendedHeight() const;
|
||||||
QByteArray getUnextendedColor() const;
|
QByteArray getUnextendedColor() const;
|
||||||
|
|
||||||
|
int getHeightSize() const { return _heightSize; }
|
||||||
|
float getHeightIncrement() const { return _heightIncrement; }
|
||||||
|
|
||||||
|
int getColorSize() const { return _colorSize; }
|
||||||
|
float getColorIncrement() const { return _colorIncrement; }
|
||||||
|
|
||||||
virtual void render(bool cursor = false);
|
virtual void render(bool cursor = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
glm::vec3 _translation;
|
glm::vec3 _translation;
|
||||||
float _scale;
|
float _scale;
|
||||||
|
Box _heightBounds;
|
||||||
|
Box _colorBounds;
|
||||||
QByteArray _height;
|
QByteArray _height;
|
||||||
QByteArray _color;
|
QByteArray _color;
|
||||||
GLuint _heightTextureID;
|
GLuint _heightTextureID;
|
||||||
GLuint _colorTextureID;
|
GLuint _colorTextureID;
|
||||||
int _heightSize;
|
int _heightSize;
|
||||||
|
float _heightIncrement;
|
||||||
|
int _colorSize;
|
||||||
|
float _colorIncrement;
|
||||||
|
|
||||||
typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair;
|
typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair;
|
||||||
static QHash<int, BufferPair> _bufferPairs;
|
static QHash<int, BufferPair> _bufferPairs;
|
||||||
|
@ -193,6 +207,8 @@ public:
|
||||||
Q_INVOKABLE BufferDataAttribute(const QString& name = QString());
|
Q_INVOKABLE BufferDataAttribute(const QString& name = QString());
|
||||||
|
|
||||||
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
|
||||||
|
|
||||||
|
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Renders metavoxels as points.
|
/// Renders metavoxels as points.
|
||||||
|
|
|
@ -55,7 +55,7 @@ AttributeRegistry::AttributeRegistry() :
|
||||||
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f;
|
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f;
|
||||||
_spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER);
|
_spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER);
|
||||||
|
|
||||||
const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 32.0f;
|
const float HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER = 40.0f;
|
||||||
_heightfieldAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
_heightfieldAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
||||||
_heightfieldColorAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
_heightfieldColorAttribute->setLODThresholdMultiplier(HEIGHTFIELD_LOD_THRESHOLD_MULTIPLIER);
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,11 @@ Box::Box(const glm::vec3& minimum, const glm::vec3& maximum) :
|
||||||
minimum(minimum), maximum(maximum) {
|
minimum(minimum), maximum(maximum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Box::add(const Box& other) {
|
||||||
|
minimum = glm::min(minimum, other.minimum);
|
||||||
|
maximum = glm::max(maximum, other.maximum);
|
||||||
|
}
|
||||||
|
|
||||||
bool Box::contains(const glm::vec3& point) const {
|
bool Box::contains(const glm::vec3& point) const {
|
||||||
return point.x >= minimum.x && point.x <= maximum.x &&
|
return point.x >= minimum.x && point.x <= maximum.x &&
|
||||||
point.y >= minimum.y && point.y <= maximum.y &&
|
point.y >= minimum.y && point.y <= maximum.y &&
|
||||||
|
|
|
@ -44,6 +44,8 @@ public:
|
||||||
|
|
||||||
explicit Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3());
|
explicit Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3());
|
||||||
|
|
||||||
|
void add(const Box& other);
|
||||||
|
|
||||||
bool contains(const glm::vec3& point) const;
|
bool contains(const glm::vec3& point) const;
|
||||||
|
|
||||||
bool contains(const Box& other) const;
|
bool contains(const Box& other) const;
|
||||||
|
|
Loading…
Reference in a new issue