Cleanup on aisle three! Removed the color/normal/voxelized spanner bits, as

well as the throbbing/scripted guides and the notion of spanner masking.
This commit is contained in:
Andrzej Kapolka 2014-11-06 19:15:43 -08:00
parent ae71bb671b
commit e08a0144c2
14 changed files with 75 additions and 1547 deletions

View file

@ -1,31 +0,0 @@
#version 120
//
// metavoxel_point.vert
// vertex shader
//
// Created by Andrzej Kapolka on 12/12/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
uniform float pointScale;
// the interpolated normal
varying vec4 normal;
void main(void) {
// transform and store the normal for interpolation
normal = vec4(normalize(gl_NormalMatrix * gl_Normal), 0.0);
// extract the first three components of the vertex for position
gl_Position = gl_ModelViewProjectionMatrix * vec4(gl_Vertex.xyz, 1.0);
// the final component is the size in world space
gl_PointSize = pointScale * gl_Vertex.w / gl_Position.w;
// copy the color for interpolation
gl_FrontColor = vec4(gl_Color.rgb, 0.0);
}

View file

@ -37,8 +37,6 @@ REGISTER_META_OBJECT(SphereRenderer)
REGISTER_META_OBJECT(CuboidRenderer)
REGISTER_META_OBJECT(StaticModelRenderer)
static int bufferPointVectorMetaTypeId = qRegisterMetaType<BufferPointVector>();
MetavoxelSystem::NetworkSimulation::NetworkSimulation(float dropRate, float repeatRate,
int minimumDelay, int maximumDelay, int bandwidthLimit) :
dropRate(dropRate),
@ -59,8 +57,6 @@ void MetavoxelSystem::init() {
MetavoxelClientManager::init();
DefaultMetavoxelRendererImplementation::init();
_pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer"));
_heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(
new BufferDataAttribute("heightfieldBuffer"));
_heightfieldBufferAttribute->setLODThresholdMultiplier(
@ -920,36 +916,6 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) {
BufferData::~BufferData() {
}
PointBuffer::PointBuffer(const BufferPointVector& points) :
_points(points) {
}
void PointBuffer::render(bool cursor) {
// initialize buffer, etc. on first render
if (!_buffer.isCreated()) {
_buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
_buffer.create();
_buffer.bind();
_pointCount = _points.size();
_buffer.allocate(_points.constData(), _pointCount * sizeof(BufferPoint));
_points.clear();
_buffer.release();
}
if (_pointCount == 0) {
return;
}
_buffer.bind();
BufferPoint* point = 0;
glVertexPointer(4, GL_FLOAT, sizeof(BufferPoint), &point->vertex);
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color);
glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal);
glDrawArrays(GL_POINTS, 0, _pointCount);
_buffer.release();
}
const int HeightfieldBuffer::HEIGHT_BORDER = 1;
const int HeightfieldBuffer::SHARED_EDGE = 1;
const int HeightfieldBuffer::HEIGHT_EXTENSION = 2 * HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE;
@ -1576,17 +1542,7 @@ AttributeValue BufferDataAttribute::inherit(const AttributeValue& parentValue) c
}
void DefaultMetavoxelRendererImplementation::init() {
if (!_pointProgram.isLinked()) {
_pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
"shaders/metavoxel_point.vert");
_pointProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
"shaders/metavoxel_voxel_base.frag");
_pointProgram.link();
_pointProgram.bind();
_pointScaleLocation = _pointProgram.uniformLocation("pointScale");
_pointProgram.release();
if (!_baseHeightfieldProgram.isLinked()) {
_baseHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
"shaders/metavoxel_heightfield_base.vert");
_baseHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
@ -1631,76 +1587,6 @@ void DefaultMetavoxelRendererImplementation::init() {
DefaultMetavoxelRendererImplementation::DefaultMetavoxelRendererImplementation() {
}
class PointAugmentVisitor : public MetavoxelVisitor {
public:
PointAugmentVisitor(const MetavoxelLOD& lod);
virtual void prepare(MetavoxelData* data);
virtual int visit(MetavoxelInfo& info);
virtual bool postVisit(MetavoxelInfo& info);
private:
BufferPointVector _points;
float _pointLeafSize;
};
PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) :
MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() <<
AttributeRegistry::getInstance()->getNormalAttribute(), QVector<AttributePointer>() <<
Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod) {
}
const int ALPHA_RENDER_THRESHOLD = 0;
void PointAugmentVisitor::prepare(MetavoxelData* data) {
MetavoxelVisitor::prepare(data);
const float MAX_POINT_LEAF_SIZE = 64.0f;
_pointLeafSize = qMin(data->getSize(), MAX_POINT_LEAF_SIZE);
}
int PointAugmentVisitor::visit(MetavoxelInfo& info) {
if (!info.isLeaf) {
return (info.size > _pointLeafSize) ? DEFAULT_ORDER : (DEFAULT_ORDER | ALL_NODES_REST);
}
QRgb color = info.inputValues.at(0).getInlineValue<QRgb>();
quint8 alpha = qAlpha(color);
if (alpha > ALPHA_RENDER_THRESHOLD) {
QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>();
BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
{ quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) },
{ quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } };
_points.append(point);
}
if (info.size >= _pointLeafSize) {
PointBuffer* buffer = NULL;
if (!_points.isEmpty()) {
BufferPointVector swapPoints;
_points.swap(swapPoints);
buffer = new PointBuffer(swapPoints);
}
BufferDataPointer pointer(buffer);
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer));
}
return STOP_RECURSION;
}
bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) {
if (info.size != _pointLeafSize) {
return false;
}
PointBuffer* buffer = NULL;
if (!_points.isEmpty()) {
BufferPointVector swapPoints;
_points.swap(swapPoints);
buffer = new PointBuffer(swapPoints);
}
BufferDataPointer pointer(buffer);
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer));
return true;
}
class HeightfieldFetchVisitor : public MetavoxelVisitor {
public:
@ -2749,15 +2635,9 @@ void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const
while (expandedPrevious.getSize() < data.getSize()) {
expandedPrevious.expand();
}
const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute();
MetavoxelNode* root = expandedPrevious.getRoot(pointBufferAttribute);
if (root) {
data.setRoot(pointBufferAttribute, root);
root->incrementReferenceCount();
}
const AttributePointer& heightfieldBufferAttribute =
Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute();
root = expandedPrevious.getRoot(heightfieldBufferAttribute);
MetavoxelNode* root = expandedPrevious.getRoot(heightfieldBufferAttribute);
if (root) {
data.setRoot(heightfieldBufferAttribute, root);
root->incrementReferenceCount();
@ -2769,10 +2649,6 @@ void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const
data.setRoot(voxelBufferAttribute, root);
root->incrementReferenceCount();
}
PointAugmentVisitor pointAugmentVisitor(lod);
data.guideToDifferent(expandedPrevious, pointAugmentVisitor);
HeightfieldRegionVisitor heightfieldRegionVisitor(lod);
data.guideToDifferent(expandedPrevious, heightfieldRegionVisitor);
@ -2789,7 +2665,7 @@ public:
SpannerSimulateVisitor(float deltaTime, const MetavoxelLOD& lod);
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
virtual bool visit(Spanner* spanner);
private:
@ -2798,11 +2674,11 @@ private:
SpannerSimulateVisitor::SpannerSimulateVisitor(float deltaTime, const MetavoxelLOD& lod) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(), lod),
QVector<AttributePointer>(), QVector<AttributePointer>(), lod),
_deltaTime(deltaTime) {
}
bool SpannerSimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
bool SpannerSimulateVisitor::visit(Spanner* spanner) {
spanner->getRenderer()->simulate(_deltaTime);
return true;
}
@ -2819,7 +2695,7 @@ public:
SpannerRenderVisitor(const MetavoxelLOD& lod);
virtual int visit(MetavoxelInfo& info);
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
virtual bool visit(Spanner* spanner);
private:
@ -2828,8 +2704,8 @@ private:
SpannerRenderVisitor::SpannerRenderVisitor(const MetavoxelLOD& lod) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(),
lod, encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())),
QVector<AttributePointer>(), QVector<AttributePointer>(), lod,
encodeOrder(Application::getInstance()->getDisplayViewFrustum()->getDirection())),
_containmentDepth(INT_MAX) {
}
@ -2845,9 +2721,9 @@ int SpannerRenderVisitor::visit(MetavoxelInfo& info) {
return SpannerVisitor::visit(info);
}
bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
bool SpannerRenderVisitor::visit(Spanner* spanner) {
const glm::vec4 OPAQUE_WHITE(1.0f, 1.0f, 1.0f, 1.0f);
spanner->getRenderer()->render(OPAQUE_WHITE, SpannerRenderer::DEFAULT_MODE, clipMinimum, clipSize);
spanner->getRenderer()->render(OPAQUE_WHITE, SpannerRenderer::DEFAULT_MODE);
return true;
}
@ -2893,40 +2769,10 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
SpannerRenderVisitor spannerRenderVisitor(lod);
data.guide(spannerRenderVisitor);
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
const int VIEWPORT_WIDTH_INDEX = 2;
const int VIEWPORT_HEIGHT_INDEX = 3;
float viewportWidth = viewport[VIEWPORT_WIDTH_INDEX];
float viewportHeight = viewport[VIEWPORT_HEIGHT_INDEX];
float viewportDiagonal = sqrtf(viewportWidth * viewportWidth + viewportHeight * viewportHeight);
float worldDiagonal = glm::distance(Application::getInstance()->getDisplayViewFrustum()->getNearBottomLeft(),
Application::getInstance()->getDisplayViewFrustum()->getNearTopRight());
_pointProgram.bind();
_pointProgram.setUniformValue(_pointScaleLocation, viewportDiagonal *
Application::getInstance()->getDisplayViewFrustum()->getNearClip() / worldDiagonal);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
glDisable(GL_BLEND);
BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute());
data.guide(pointRenderVisitor);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
_pointProgram.release();
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
glEnableClientState(GL_VERTEX_ARRAY);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_EQUAL, 0.0f);
@ -2994,8 +2840,6 @@ void DefaultMetavoxelRendererImplementation::loadSplatProgram(const char* type,
program.release();
}
ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram;
int DefaultMetavoxelRendererImplementation::_pointScaleLocation;
ProgramObject DefaultMetavoxelRendererImplementation::_baseHeightfieldProgram;
int DefaultMetavoxelRendererImplementation::_baseHeightScaleLocation;
int DefaultMetavoxelRendererImplementation::_baseColorScaleLocation;
@ -3007,55 +2851,10 @@ ProgramObject DefaultMetavoxelRendererImplementation::_splatVoxelProgram;
DefaultMetavoxelRendererImplementation::SplatLocations DefaultMetavoxelRendererImplementation::_splatVoxelLocations;
ProgramObject DefaultMetavoxelRendererImplementation::_voxelCursorProgram;
static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
GLdouble coefficients[] = { x, y, z, w };
glClipPlane(plane, coefficients);
glEnable(plane);
}
void ClippedRenderer::render(const glm::vec4& color, Mode mode, const glm::vec3& clipMinimum, float clipSize) {
if (clipSize == 0.0f) {
renderUnclipped(color, mode);
return;
}
enableClipPlane(GL_CLIP_PLANE0, -1.0f, 0.0f, 0.0f, clipMinimum.x + clipSize);
enableClipPlane(GL_CLIP_PLANE1, 1.0f, 0.0f, 0.0f, -clipMinimum.x);
enableClipPlane(GL_CLIP_PLANE2, 0.0f, -1.0f, 0.0f, clipMinimum.y + clipSize);
enableClipPlane(GL_CLIP_PLANE3, 0.0f, 1.0f, 0.0f, -clipMinimum.y);
enableClipPlane(GL_CLIP_PLANE4, 0.0f, 0.0f, -1.0f, clipMinimum.z + clipSize);
enableClipPlane(GL_CLIP_PLANE5, 0.0f, 0.0f, 1.0f, -clipMinimum.z);
renderUnclipped(color, mode);
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
glDisable(GL_CLIP_PLANE4);
glDisable(GL_CLIP_PLANE5);
}
SphereRenderer::SphereRenderer() {
}
void SphereRenderer::render(const glm::vec4& color, Mode mode, const glm::vec3& clipMinimum, float clipSize) {
if (clipSize == 0.0f) {
renderUnclipped(color, mode);
return;
}
// slight performance optimization: don't render if clip bounds are entirely within sphere
Sphere* sphere = static_cast<Sphere*>(_spanner);
Box clipBox(clipMinimum, clipMinimum + glm::vec3(clipSize, clipSize, clipSize));
for (int i = 0; i < Box::VERTEX_COUNT; i++) {
const float CLIP_PROPORTION = 0.95f;
if (glm::distance(sphere->getTranslation(), clipBox.getVertex(i)) >= sphere->getScale() * CLIP_PROPORTION) {
ClippedRenderer::render(color, mode, clipMinimum, clipSize);
return;
}
}
}
void SphereRenderer::renderUnclipped(const glm::vec4& color, Mode mode) {
void SphereRenderer::render(const glm::vec4& color, Mode mode) {
Sphere* sphere = static_cast<Sphere*>(_spanner);
const QColor& ownColor = sphere->getColor();
glColor4f(ownColor.redF() * color.r, ownColor.greenF() * color.g, ownColor.blueF() * color.b, ownColor.alphaF() * color.a);
@ -3075,7 +2874,7 @@ void SphereRenderer::renderUnclipped(const glm::vec4& color, Mode mode) {
CuboidRenderer::CuboidRenderer() {
}
void CuboidRenderer::renderUnclipped(const glm::vec4& color, Mode mode) {
void CuboidRenderer::render(const glm::vec4& color, Mode mode) {
Cuboid* cuboid = static_cast<Cuboid*>(_spanner);
const QColor& ownColor = cuboid->getColor();
glColor4f(ownColor.redF() * color.r, ownColor.greenF() * color.g, ownColor.blueF() * color.b, ownColor.alphaF() * color.a);
@ -3126,7 +2925,7 @@ void StaticModelRenderer::simulate(float deltaTime) {
_model->simulate(deltaTime);
}
void StaticModelRenderer::renderUnclipped(const glm::vec4& color, Mode mode) {
void StaticModelRenderer::render(const glm::vec4& color, Mode mode) {
switch (mode) {
case DIFFUSE_MODE:
_model->render(color.a, Model::DIFFUSE_RENDER_MODE);
@ -3143,8 +2942,7 @@ void StaticModelRenderer::renderUnclipped(const glm::vec4& color, Mode mode) {
_model->render(color.a);
}
bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
RayIntersectionInfo info;
info._rayStart = origin;
info._rayDirection = direction;

View file

@ -54,7 +54,6 @@ public:
void setNetworkSimulation(const NetworkSimulation& simulation);
NetworkSimulation getNetworkSimulation();
const AttributePointer& getPointBufferAttribute() { return _pointBufferAttribute; }
const AttributePointer& getHeightfieldBufferAttribute() { return _heightfieldBufferAttribute; }
const AttributePointer& getVoxelBufferAttribute() { return _voxelBufferAttribute; }
@ -103,7 +102,6 @@ private:
void guideToAugmented(MetavoxelVisitor& visitor, bool render = false);
AttributePointer _pointBufferAttribute;
AttributePointer _heightfieldBufferAttribute;
AttributePointer _voxelBufferAttribute;
@ -124,18 +122,6 @@ public slots:
virtual void handle() = 0;
};
/// Describes contents of a point in a point buffer.
class BufferPoint {
public:
glm::vec4 vertex;
quint8 color[3];
quint8 normal[3];
};
typedef QVector<BufferPoint> BufferPointVector;
Q_DECLARE_METATYPE(BufferPointVector)
/// Simple throttle for limiting bandwidth on a per-second basis.
class Throttle {
public:
@ -203,21 +189,6 @@ public:
typedef QExplicitlySharedDataPointer<BufferData> BufferDataPointer;
/// Contains the information necessary to render a group of points.
class PointBuffer : public BufferData {
public:
PointBuffer(const BufferPointVector& points);
virtual void render(bool cursor = false);
private:
BufferPointVector _points;
QOpenGLBuffer _buffer;
int _pointCount;
};
/// Contains the information necessary to render a heightfield block.
class HeightfieldBuffer : public BufferData {
public:
@ -369,9 +340,6 @@ public:
static void init();
static ProgramObject& getPointProgram() { return _pointProgram; }
static int getPointScaleLocation() { return _pointScaleLocation; }
static ProgramObject& getBaseHeightfieldProgram() { return _baseHeightfieldProgram; }
static int getBaseHeightScaleLocation() { return _baseHeightScaleLocation; }
static int getBaseColorScaleLocation() { return _baseColorScaleLocation; }
@ -411,9 +379,6 @@ private:
static void loadSplatProgram(const char* type, ProgramObject& program, SplatLocations& locations);
static ProgramObject _pointProgram;
static int _pointScaleLocation;
static ProgramObject _baseHeightfieldProgram;
static int _baseHeightScaleLocation;
static int _baseColorScaleLocation;
@ -438,49 +403,30 @@ private:
static ProgramObject _voxelCursorProgram;
};
/// Base class for spanner renderers; provides clipping.
class ClippedRenderer : public SpannerRenderer {
Q_OBJECT
public:
virtual void render(const glm::vec4& color, Mode mode, const glm::vec3& clipMinimum, float clipSize);
protected:
virtual void renderUnclipped(const glm::vec4& color, Mode mode) = 0;
};
/// Renders spheres.
class SphereRenderer : public ClippedRenderer {
class SphereRenderer : public SpannerRenderer {
Q_OBJECT
public:
Q_INVOKABLE SphereRenderer();
virtual void render(const glm::vec4& color, Mode mode, const glm::vec3& clipMinimum, float clipSize);
protected:
virtual void renderUnclipped(const glm::vec4& color, Mode mode);
virtual void render(const glm::vec4& color, Mode mode);
};
/// Renders cuboids.
class CuboidRenderer : public ClippedRenderer {
class CuboidRenderer : public SpannerRenderer {
Q_OBJECT
public:
Q_INVOKABLE CuboidRenderer();
protected:
virtual void renderUnclipped(const glm::vec4& color, Mode mode);
virtual void render(const glm::vec4& color, Mode mode);
};
/// Renders static models.
class StaticModelRenderer : public ClippedRenderer {
class StaticModelRenderer : public SpannerRenderer {
Q_OBJECT
public:
@ -489,12 +435,8 @@ public:
virtual void init(Spanner* spanner);
virtual void simulate(float deltaTime);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
protected:
virtual void renderUnclipped(const glm::vec4& color, Mode mode);
virtual void render(const glm::vec4& color, Mode mode);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
private slots:

View file

@ -122,7 +122,6 @@ MetavoxelEditor::MetavoxelEditor() :
addTool(new InsertSpannerTool(this));
addTool(new RemoveSpannerTool(this));
addTool(new ClearSpannersTool(this));
addTool(new SetSpannerTool(this));
addTool(new HeightfieldHeightBrushTool(this));
addTool(new HeightfieldMaterialBrushTool(this));
addTool(new ImportHeightfieldTool(this));
@ -241,7 +240,7 @@ void MetavoxelEditor::createNewAttribute() {
form.addRow("Name:", &name);
SharedObjectEditor editor(&Attribute::staticMetaObject, false);
editor.setObject(new QRgbAttribute());
editor.setObject(new FloatAttribute());
layout.addWidget(&editor);
QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
@ -622,7 +621,7 @@ void PlaceSpannerTool::render() {
const float SPANNER_ALPHA = 0.25f;
QColor color = getColor();
spanner->getRenderer()->render(glm::vec4(color.redF(), color.greenF(), color.blueF(), SPANNER_ALPHA),
SpannerRenderer::DEFAULT_MODE, glm::vec3(), 0.0f);
SpannerRenderer::DEFAULT_MODE);
}
bool PlaceSpannerTool::appliesTo(const AttributePointer& attribute) const {
@ -712,244 +711,6 @@ void ClearSpannersTool::clear() {
Application::getInstance()->getMetavoxels()->applyEdit(message);
}
SetSpannerTool::SetSpannerTool(MetavoxelEditor* editor) :
PlaceSpannerTool(editor, "Set Spanner", "Set") {
}
bool SetSpannerTool::appliesTo(const AttributePointer& attribute) const {
return attribute == AttributeRegistry::getInstance()->getSpannersAttribute();
}
glm::quat DIRECTION_ROTATIONS[] = {
rotationBetween(glm::vec3(-1.0f, 0.0f, 0.0f), IDENTITY_FRONT),
rotationBetween(glm::vec3(1.0f, 0.0f, 0.0f), IDENTITY_FRONT),
rotationBetween(glm::vec3(0.0f, -1.0f, 0.0f), IDENTITY_FRONT),
rotationBetween(glm::vec3(0.0f, 1.0f, 0.0f), IDENTITY_FRONT),
rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), IDENTITY_FRONT),
rotationBetween(glm::vec3(0.0f, 0.0f, 1.0f), IDENTITY_FRONT) };
/// Represents a view from one direction of the spanner to be voxelized.
class DirectionImages {
public:
QImage color;
QVector<float> depth;
glm::vec3 minima;
glm::vec3 maxima;
glm::vec3 scale;
};
class Voxelizer : public QRunnable {
public:
Voxelizer(float size, const Box& bounds, float granularity, const QVector<DirectionImages>& directionImages);
virtual void run();
private:
void voxelize(const glm::vec3& center);
float _size;
Box _bounds;
float _granularity;
QVector<DirectionImages> _directionImages;
};
Voxelizer::Voxelizer(float size, const Box& bounds, float granularity, const QVector<DirectionImages>& directionImages) :
_size(size),
_bounds(bounds),
_granularity(granularity),
_directionImages(directionImages) {
}
void Voxelizer::run() {
// voxelize separately each cell within the bounds
float halfSize = _size * 0.5f;
for (float x = _bounds.minimum.x + halfSize; x < _bounds.maximum.x; x += _size) {
for (float y = _bounds.minimum.y + halfSize; y < _bounds.maximum.y; y += _size) {
for (float z = _bounds.minimum.z + halfSize; z < _bounds.maximum.z; z += _size) {
voxelize(glm::vec3(x, y, z));
}
}
}
}
class VoxelizationVisitor : public MetavoxelVisitor {
public:
VoxelizationVisitor(const QVector<DirectionImages>& directionImages, const glm::vec3& center, float granularity);
virtual int visit(MetavoxelInfo& info);
private:
QVector<DirectionImages> _directionImages;
glm::vec3 _center;
float _granularity;
};
VoxelizationVisitor::VoxelizationVisitor(const QVector<DirectionImages>& directionImages,
const glm::vec3& center, float granularity) :
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() <<
AttributeRegistry::getInstance()->getColorAttribute()),
_directionImages(directionImages),
_center(center),
_granularity(granularity) {
}
bool checkDisjoint(const DirectionImages& images, const glm::vec3& minimum, const glm::vec3& maximum, float extent) {
for (int x = qMax(0, (int)minimum.x), xmax = qMin(images.color.width(), (int)maximum.x); x < xmax; x++) {
for (int y = qMax(0, (int)minimum.y), ymax = qMin(images.color.height(), (int)maximum.y); y < ymax; y++) {
float depth = 1.0f - images.depth.at(y * images.color.width() + x);
if (depth - minimum.z >= -extent - EPSILON) {
return false;
}
}
}
return true;
}
int VoxelizationVisitor::visit(MetavoxelInfo& info) {
float halfSize = info.size * 0.5f;
glm::vec3 center = info.minimum + _center + glm::vec3(halfSize, halfSize, halfSize);
const float EXTENT_SCALE = 2.0f;
if (info.size > _granularity) {
for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) {
glm::vec3 rotated = DIRECTION_ROTATIONS[i] * center;
const DirectionImages& images = _directionImages.at(i);
glm::vec3 relative = (rotated - images.minima) * images.scale;
glm::vec3 extents = images.scale * halfSize;
glm::vec3 minimum = relative - extents;
glm::vec3 maximum = relative + extents;
if (checkDisjoint(images, minimum, maximum, extents.z * EXTENT_SCALE)) {
info.outputValues[0] = AttributeValue(_outputs.at(0));
return STOP_RECURSION;
}
}
return DEFAULT_ORDER;
}
QRgb closestColor = QRgb();
float closestDistance = FLT_MAX;
for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) {
glm::vec3 rotated = DIRECTION_ROTATIONS[i] * center;
const DirectionImages& images = _directionImages.at(i);
glm::vec3 relative = (rotated - images.minima) * images.scale;
int x = qMax(qMin((int)glm::round(relative.x), images.color.width() - 1), 0);
int y = qMax(qMin((int)glm::round(relative.y), images.color.height() - 1), 0);
float depth = 1.0f - images.depth.at(y * images.color.width() + x);
float distance = depth - relative.z;
float extent = images.scale.z * halfSize * EXTENT_SCALE;
if (distance < -extent - EPSILON) {
info.outputValues[0] = AttributeValue(_outputs.at(0));
return STOP_RECURSION;
}
QRgb color = images.color.pixel(x, y);
if (distance < extent + EPSILON) {
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<QRgb>(color));
return STOP_RECURSION;
}
if (distance < closestDistance) {
closestColor = color;
closestDistance = distance;
}
}
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<QRgb>(closestColor));
return STOP_RECURSION;
}
void Voxelizer::voxelize(const glm::vec3& center) {
MetavoxelData data;
data.setSize(_size);
VoxelizationVisitor visitor(_directionImages, center, _granularity);
data.guide(visitor);
MetavoxelEditMessage edit = { QVariant::fromValue(SetDataEdit(
center - glm::vec3(_size, _size, _size) * 0.5f, data, true)) };
QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "applyEdit",
Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, true));
}
void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) {
Spanner* spannerData = static_cast<Spanner*>(spanner.data());
Box bounds = spannerData->getBounds();
float longestSide(qMax(bounds.getLongestSide(), spannerData->getPlacementGranularity()));
float size = powf(2.0f, floorf(logf(longestSide) / logf(2.0f)));
Box cellBounds(glm::floor(bounds.minimum / size) * size, glm::ceil(bounds.maximum / size) * size);
Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind();
glEnable(GL_SCISSOR_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
QVector<DirectionImages> directionImages;
for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) {
glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX);
glm::vec3 maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int j = 0; j < Box::VERTEX_COUNT; j++) {
glm::vec3 rotated = DIRECTION_ROTATIONS[i] * cellBounds.getVertex(j);
minima = glm::min(minima, rotated);
maxima = glm::max(maxima, rotated);
}
float renderGranularity = spannerData->getVoxelizationGranularity() / 4.0f;
int width = glm::round((maxima.x - minima.x) / renderGranularity);
int height = glm::round((maxima.y - minima.y) / renderGranularity);
glViewport(0, 0, width, height);
glScissor(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glm::vec3 axis = glm::axis(DIRECTION_ROTATIONS[i]);
glRotatef(glm::degrees(glm::angle(DIRECTION_ROTATIONS[i])), axis.x, axis.y, axis.z);
Application::getInstance()->setupWorldLight();
Application::getInstance()->updateUntranslatedViewMatrix();
const glm::vec4 OPAQUE_WHITE(1.0f, 1.0f, 1.0f, 1.0f);
spannerData->getRenderer()->render(OPAQUE_WHITE, SpannerRenderer::DIFFUSE_MODE, glm::vec3(), 0.0f);
DirectionImages images = { QImage(width, height, QImage::Format_ARGB32),
QVector<float>(width * height), minima, maxima, glm::vec3(width / (maxima.x - minima.x),
height / (maxima.y - minima.y), 1.0f / (maxima.z - minima.z)) };
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, images.color.bits());
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, images.depth.data());
directionImages.append(images);
glMatrixMode(GL_PROJECTION);
}
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_BLEND);
glDisable(GL_SCISSOR_TEST);
Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->release();
glViewport(0, 0, Application::getInstance()->getGLWidget()->getDeviceWidth(),
Application::getInstance()->getGLWidget()->getDeviceHeight());
// send the images off to the lab for processing
QThreadPool::globalInstance()->start(new Voxelizer(size, cellBounds,
spannerData->getVoxelizationGranularity(), directionImages));
}
HeightfieldTool::HeightfieldTool(MetavoxelEditor* editor, const QString& name) :
MetavoxelTool(editor, name, false) {

View file

@ -242,21 +242,6 @@ private slots:
void clear();
};
/// Allows setting the value by placing a spanner.
class SetSpannerTool : public PlaceSpannerTool {
Q_OBJECT
public:
SetSpannerTool(MetavoxelEditor* editor);
virtual bool appliesTo(const AttributePointer& attribute) const;
protected:
virtual void applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner);
};
/// Base class for heightfield tools.
class HeightfieldTool : public MetavoxelTool {
Q_OBJECT

View file

@ -19,10 +19,6 @@
#include "MetavoxelData.h"
REGISTER_META_OBJECT(FloatAttribute)
REGISTER_META_OBJECT(QRgbAttribute)
REGISTER_META_OBJECT(PackedNormalAttribute)
REGISTER_META_OBJECT(SpannerQRgbAttribute)
REGISTER_META_OBJECT(SpannerPackedNormalAttribute)
REGISTER_META_OBJECT(MaterialObject)
REGISTER_META_OBJECT(HeightfieldAttribute)
REGISTER_META_OBJECT(HeightfieldColorAttribute)
@ -48,11 +44,6 @@ AttributeRegistry::AttributeRegistry() :
_rendererAttribute(registerAttribute(new SharedObjectAttribute("renderer", &MetavoxelRenderer::staticMetaObject,
new DefaultMetavoxelRenderer()))),
_spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))),
_colorAttribute(registerAttribute(new QRgbAttribute("color"))),
_normalAttribute(registerAttribute(new PackedNormalAttribute("normal"))),
_spannerColorAttribute(registerAttribute(new SpannerQRgbAttribute("spannerColor"))),
_spannerNormalAttribute(registerAttribute(new SpannerPackedNormalAttribute("spannerNormal"))),
_spannerMaskAttribute(registerAttribute(new FloatAttribute("spannerMask"))),
_heightfieldAttribute(registerAttribute(new HeightfieldAttribute("heightfield"))),
_heightfieldColorAttribute(registerAttribute(new HeightfieldColorAttribute("heightfieldColor"))),
_heightfieldMaterialAttribute(registerAttribute(new HeightfieldMaterialAttribute("heightfieldMaterial"))),
@ -89,8 +80,6 @@ static QScriptValue qDebugFunction(QScriptContext* context, QScriptEngine* engin
void AttributeRegistry::configureScriptEngine(QScriptEngine* engine) {
QScriptValue registry = engine->newObject();
registry.setProperty("colorAttribute", engine->newQObject(_colorAttribute.data()));
registry.setProperty("normalAttribute", engine->newQObject(_normalAttribute.data()));
registry.setProperty("getAttribute", engine->newFunction(getAttribute, 1));
engine->globalObject().setProperty("AttributeRegistry", registry);
engine->globalObject().setProperty("qDebug", engine->newFunction(qDebugFunction, 1));
@ -292,111 +281,8 @@ MetavoxelNode* Attribute::expandMetavoxelRoot(const MetavoxelNode& root) {
return newParent;
}
FloatAttribute::FloatAttribute(const QString& name, float defaultValue) :
SimpleInlineAttribute<float>(name, defaultValue) {
}
QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) :
InlineAttribute<QRgb>(name, defaultValue) {
}
bool QRgbAttribute::merge(void*& parent, void* children[], bool postRead) const {
QRgb firstValue = decodeInline<QRgb>(children[0]);
int totalAlpha = qAlpha(firstValue);
int totalRed = qRed(firstValue) * totalAlpha;
int totalGreen = qGreen(firstValue) * totalAlpha;
int totalBlue = qBlue(firstValue) * totalAlpha;
bool allChildrenEqual = true;
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
QRgb value = decodeInline<QRgb>(children[i]);
int alpha = qAlpha(value);
totalRed += qRed(value) * alpha;
totalGreen += qGreen(value) * alpha;
totalBlue += qBlue(value) * alpha;
totalAlpha += alpha;
allChildrenEqual &= (firstValue == value);
}
if (totalAlpha == 0) {
parent = encodeInline(QRgb());
} else {
parent = encodeInline(qRgba(totalRed / totalAlpha, totalGreen / totalAlpha,
totalBlue / totalAlpha, totalAlpha / MERGE_COUNT));
}
return allChildrenEqual;
}
void* QRgbAttribute::mix(void* first, void* second, float alpha) const {
QRgb firstValue = decodeInline<QRgb>(first);
QRgb secondValue = decodeInline<QRgb>(second);
return encodeInline(qRgba(
glm::mix((float)qRed(firstValue), (float)qRed(secondValue), alpha),
glm::mix((float)qGreen(firstValue), (float)qGreen(secondValue), alpha),
glm::mix((float)qBlue(firstValue), (float)qBlue(secondValue), alpha),
glm::mix((float)qAlpha(firstValue), (float)qAlpha(secondValue), alpha)));
}
const float EIGHT_BIT_MAXIMUM = 255.0f;
void* QRgbAttribute::blend(void* source, void* dest) const {
QRgb sourceValue = decodeInline<QRgb>(source);
QRgb destValue = decodeInline<QRgb>(dest);
float alpha = qAlpha(sourceValue) / EIGHT_BIT_MAXIMUM;
return encodeInline(qRgba(
glm::mix((float)qRed(destValue), (float)qRed(sourceValue), alpha),
glm::mix((float)qGreen(destValue), (float)qGreen(sourceValue), alpha),
glm::mix((float)qBlue(destValue), (float)qBlue(sourceValue), alpha),
glm::mix((float)qAlpha(destValue), (float)qAlpha(sourceValue), alpha)));
}
void* QRgbAttribute::createFromScript(const QScriptValue& value, QScriptEngine* engine) const {
return encodeInline((QRgb)value.toUInt32());
}
void* QRgbAttribute::createFromVariant(const QVariant& value) const {
switch (value.userType()) {
case QMetaType::QColor:
return encodeInline(value.value<QColor>().rgba());
default:
return encodeInline((QRgb)value.toUInt());
}
}
QWidget* QRgbAttribute::createEditor(QWidget* parent) const {
QColorEditor* editor = new QColorEditor(parent);
editor->setColor(QColor::fromRgba(_defaultValue));
return editor;
}
PackedNormalAttribute::PackedNormalAttribute(const QString& name, QRgb defaultValue) :
QRgbAttribute(name, defaultValue) {
}
bool PackedNormalAttribute::merge(void*& parent, void* children[], bool postRead) const {
QRgb firstValue = decodeInline<QRgb>(children[0]);
glm::vec3 total = unpackNormal(firstValue) * (float)qAlpha(firstValue);
bool allChildrenEqual = true;
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
QRgb value = decodeInline<QRgb>(children[i]);
total += unpackNormal(value) * (float)qAlpha(value);
allChildrenEqual &= (firstValue == value);
}
float length = glm::length(total);
parent = encodeInline(length < EPSILON ? QRgb() : packNormal(total / length));
return allChildrenEqual;
}
void* PackedNormalAttribute::mix(void* first, void* second, float alpha) const {
glm::vec3 firstNormal = unpackNormal(decodeInline<QRgb>(first));
glm::vec3 secondNormal = unpackNormal(decodeInline<QRgb>(second));
return encodeInline(packNormal(glm::normalize(glm::mix(firstNormal, secondNormal, alpha))));
}
void* PackedNormalAttribute::blend(void* source, void* dest) const {
QRgb sourceValue = decodeInline<QRgb>(source);
QRgb destValue = decodeInline<QRgb>(dest);
float alpha = qAlpha(sourceValue) / EIGHT_BIT_MAXIMUM;
return encodeInline(packNormal(glm::normalize(glm::mix(unpackNormal(destValue), unpackNormal(sourceValue), alpha))));
FloatAttribute::FloatAttribute(const QString& name) :
SimpleInlineAttribute(name) {
}
const float CHAR_SCALE = 127.0f;
@ -415,106 +301,6 @@ glm::vec3 unpackNormal(QRgb value) {
(char)qBlue(value) * INVERSE_CHAR_SCALE);
}
SpannerQRgbAttribute::SpannerQRgbAttribute(const QString& name, QRgb defaultValue) :
QRgbAttribute(name, defaultValue) {
}
void SpannerQRgbAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
value = getDefaultValue();
in.read(&value, 32);
}
void SpannerQRgbAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
out.write(&value, 32);
}
MetavoxelNode* SpannerQRgbAttribute::createMetavoxelNode(
const AttributeValue& value, const MetavoxelNode* original) const {
return new MetavoxelNode(value, original);
}
bool SpannerQRgbAttribute::merge(void*& parent, void* children[], bool postRead) const {
if (postRead) {
for (int i = 0; i < MERGE_COUNT; i++) {
if (qAlpha(decodeInline<QRgb>(children[i])) != 0) {
return false;
}
}
return true;
}
QRgb parentValue = decodeInline<QRgb>(parent);
int totalAlpha = qAlpha(parentValue) * Attribute::MERGE_COUNT;
int totalRed = qRed(parentValue) * totalAlpha;
int totalGreen = qGreen(parentValue) * totalAlpha;
int totalBlue = qBlue(parentValue) * totalAlpha;
bool allChildrenTransparent = true;
for (int i = 0; i < Attribute::MERGE_COUNT; i++) {
QRgb value = decodeInline<QRgb>(children[i]);
int alpha = qAlpha(value);
totalRed += qRed(value) * alpha;
totalGreen += qGreen(value) * alpha;
totalBlue += qBlue(value) * alpha;
totalAlpha += alpha;
allChildrenTransparent &= (alpha == 0);
}
if (totalAlpha == 0) {
parent = encodeInline(QRgb());
} else {
parent = encodeInline(qRgba(totalRed / totalAlpha, totalGreen / totalAlpha,
totalBlue / totalAlpha, totalAlpha / MERGE_COUNT));
}
return allChildrenTransparent;
}
AttributeValue SpannerQRgbAttribute::inherit(const AttributeValue& parentValue) const {
return AttributeValue(parentValue.getAttribute());
}
SpannerPackedNormalAttribute::SpannerPackedNormalAttribute(const QString& name, QRgb defaultValue) :
PackedNormalAttribute(name, defaultValue) {
}
void SpannerPackedNormalAttribute::read(Bitstream& in, void*& value, bool isLeaf) const {
value = getDefaultValue();
in.read(&value, 32);
}
void SpannerPackedNormalAttribute::write(Bitstream& out, void* value, bool isLeaf) const {
out.write(&value, 32);
}
MetavoxelNode* SpannerPackedNormalAttribute::createMetavoxelNode(
const AttributeValue& value, const MetavoxelNode* original) const {
return new MetavoxelNode(value, original);
}
bool SpannerPackedNormalAttribute::merge(void*& parent, void* children[], bool postRead) const {
if (postRead) {
for (int i = 0; i < MERGE_COUNT; i++) {
if (qAlpha(decodeInline<QRgb>(children[i])) != 0) {
return false;
}
}
return true;
}
QRgb parentValue = decodeInline<QRgb>(parent);
glm::vec3 total = unpackNormal(parentValue) * (float)(qAlpha(parentValue) * Attribute::MERGE_COUNT);
bool allChildrenTransparent = true;
for (int i = 0; i < Attribute::MERGE_COUNT; i++) {
QRgb value = decodeInline<QRgb>(children[i]);
int alpha = qAlpha(value);
total += unpackNormal(value) * (float)alpha;
allChildrenTransparent &= (alpha == 0);
}
float length = glm::length(total);
parent = encodeInline(length < EPSILON ? QRgb() : packNormal(total / length));
return allChildrenTransparent;
}
AttributeValue SpannerPackedNormalAttribute::inherit(const AttributeValue& parentValue) const {
return AttributeValue(parentValue.getAttribute());
}
DataBlock::~DataBlock() {
}
@ -1426,6 +1212,8 @@ static QHash<uchar, int> countIndices(const QByteArray& contents) {
return counts;
}
const float EIGHT_BIT_MAXIMUM = 255.0f;
uchar getMaterialIndex(const SharedObjectPointer& material, QVector<SharedObjectPointer>& materials, QByteArray& contents) {
if (!(material && static_cast<MaterialObject*>(material.data())->getDiffuse().isValid())) {
return 0;

View file

@ -88,21 +88,6 @@ public:
/// Returns a reference to the standard SharedObjectSet "spanners" attribute.
const AttributePointer& getSpannersAttribute() const { return _spannersAttribute; }
/// Returns a reference to the standard QRgb "color" attribute.
const AttributePointer& getColorAttribute() const { return _colorAttribute; }
/// Returns a reference to the standard packed normal "normal" attribute.
const AttributePointer& getNormalAttribute() const { return _normalAttribute; }
/// Returns a reference to the standard QRgb "spannerColor" attribute.
const AttributePointer& getSpannerColorAttribute() const { return _spannerColorAttribute; }
/// Returns a reference to the standard packed normal "spannerNormal" attribute.
const AttributePointer& getSpannerNormalAttribute() const { return _spannerNormalAttribute; }
/// Returns a reference to the standard "spannerMask" attribute.
const AttributePointer& getSpannerMaskAttribute() const { return _spannerMaskAttribute; }
/// Returns a reference to the standard HeightfieldHeightDataPointer "heightfield" attribute.
const AttributePointer& getHeightfieldAttribute() const { return _heightfieldAttribute; }
@ -131,11 +116,6 @@ private:
AttributePointer _guideAttribute;
AttributePointer _rendererAttribute;
AttributePointer _spannersAttribute;
AttributePointer _colorAttribute;
AttributePointer _normalAttribute;
AttributePointer _spannerColorAttribute;
AttributePointer _spannerNormalAttribute;
AttributePointer _spannerMaskAttribute;
AttributePointer _heightfieldAttribute;
AttributePointer _heightfieldColorAttribute;
AttributePointer _heightfieldMaterialAttribute;
@ -366,51 +346,13 @@ template<class T, int bits> inline bool SimpleInlineAttribute<T, bits>::merge(
return allChildrenEqual;
}
/// Simple float attribute.
/// A simple float attribute.
class FloatAttribute : public SimpleInlineAttribute<float> {
Q_OBJECT
Q_PROPERTY(float defaultValue MEMBER _defaultValue)
public:
Q_INVOKABLE FloatAttribute(const QString& name = QString(), float defaultValue = 0.0f);
};
/// Provides appropriate averaging for RGBA values.
class QRgbAttribute : public InlineAttribute<QRgb> {
Q_OBJECT
Q_PROPERTY(uint defaultValue MEMBER _defaultValue)
public:
Q_INVOKABLE QRgbAttribute(const QString& name = QString(), QRgb defaultValue = QRgb());
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual void* mix(void* first, void* second, float alpha) const;
virtual void* blend(void* source, void* dest) const;
virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const;
virtual void* createFromVariant(const QVariant& value) const;
virtual QWidget* createEditor(QWidget* parent = NULL) const;
};
/// Provides appropriate averaging for packed normals.
class PackedNormalAttribute : public QRgbAttribute {
Q_OBJECT
public:
Q_INVOKABLE PackedNormalAttribute(const QString& name = QString(), QRgb defaultValue = QRgb());
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual void* mix(void* first, void* second, float alpha) const;
virtual void* blend(void* source, void* dest) const;
Q_INVOKABLE FloatAttribute(const QString& name = QString());
};
/// Packs a normal into an RGB value.
@ -422,42 +364,6 @@ QRgb packNormal(const glm::vec3& normal, int alpha);
/// Unpacks a normal from an RGB value.
glm::vec3 unpackNormal(QRgb value);
/// RGBA values for voxelized spanners.
class SpannerQRgbAttribute : public QRgbAttribute {
Q_OBJECT
public:
Q_INVOKABLE SpannerQRgbAttribute(const QString& name = QString(), QRgb defaultValue = QRgb());
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
};
/// Packed normals for voxelized spanners.
class SpannerPackedNormalAttribute : public PackedNormalAttribute {
Q_OBJECT
public:
Q_INVOKABLE SpannerPackedNormalAttribute(const QString& name = QString(), QRgb defaultValue = QRgb());
virtual void read(Bitstream& in, void*& value, bool isLeaf) const;
virtual void write(Bitstream& out, void* value, bool isLeaf) const;
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
};
typedef QExplicitlySharedDataPointer<DataBlock> DataBlockPointer;
/// Base class for blocks of data.

View file

@ -63,19 +63,6 @@ SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(cons
return closestSpanner;
}
void MetavoxelClientManager::setSphere(const glm::vec3& center, float radius, const QColor& color) {
Sphere* sphere = new Sphere();
sphere->setTranslation(center);
sphere->setScale(radius);
sphere->setColor(color);
setSpanner(sphere);
}
void MetavoxelClientManager::setSpanner(const SharedObjectPointer& object, bool reliable) {
MetavoxelEditMessage edit = { QVariant::fromValue(SetSpannerEdit(object)) };
applyEdit(edit, reliable);
}
void MetavoxelClientManager::paintHeightfieldHeight(const glm::vec3& position, float radius, float height) {
MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldHeightEdit(position, radius, height)) };
applyEdit(edit, true);

View file

@ -37,10 +37,6 @@ public:
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
const AttributePointer& attribute, float& distance);
Q_INVOKABLE void setSphere(const glm::vec3& center, float radius, const QColor& color = QColor(Qt::gray));
Q_INVOKABLE void setSpanner(const SharedObjectPointer& object, bool reliable = false);
Q_INVOKABLE void paintHeightfieldHeight(const glm::vec3& position, float radius, float height);
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);

View file

@ -11,7 +11,6 @@
#include <QDateTime>
#include <QDebugStateSaver>
#include <QScriptEngine>
#include <QThread>
#include <QtDebug>
@ -21,12 +20,9 @@
#include "MetavoxelData.h"
#include "MetavoxelUtil.h"
#include "ScriptCache.h"
REGISTER_META_OBJECT(MetavoxelGuide)
REGISTER_META_OBJECT(DefaultMetavoxelGuide)
REGISTER_META_OBJECT(ScriptedMetavoxelGuide)
REGISTER_META_OBJECT(ThrobbingMetavoxelGuide)
REGISTER_META_OBJECT(MetavoxelRenderer)
REGISTER_META_OBJECT(DefaultMetavoxelRenderer)
REGISTER_META_OBJECT(Spanner)
@ -401,7 +397,7 @@ private:
FirstRaySpannerIntersectionVisitor::FirstRaySpannerIntersectionVisitor(
const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, const MetavoxelLOD& lod) :
RaySpannerIntersectionVisitor(origin, direction, QVector<AttributePointer>() << attribute,
QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(), lod),
QVector<AttributePointer>(), QVector<AttributePointer>(), lod),
_spanner(NULL) {
}
@ -714,6 +710,7 @@ bool MetavoxelData::deepEquals(const MetavoxelData& other, const MetavoxelLOD& l
return false;
}
if (_roots.size() != other._roots.size()) {
qDebug() << _roots << other._roots;
return false;
}
glm::vec3 minimum = getMinimum();
@ -1367,12 +1364,10 @@ MetavoxelVisitation& MetavoxelVisitor::acquireVisitation() {
return _visitations[_depth];
}
SpannerVisitor::SpannerVisitor(const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& spannerMasks,
const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs,
const MetavoxelLOD& lod, int order) :
MetavoxelVisitor(inputs + spannerInputs + spannerMasks, outputs, lod),
SpannerVisitor::SpannerVisitor(const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod, int order) :
MetavoxelVisitor(inputs + spannerInputs, outputs, lod),
_spannerInputCount(spannerInputs.size()),
_spannerMaskCount(spannerMasks.size()),
_order(order) {
}
@ -1382,34 +1377,15 @@ void SpannerVisitor::prepare(MetavoxelData* data) {
}
int SpannerVisitor::visit(MetavoxelInfo& info) {
for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) {
for (int end = _inputs.size(), i = end - _spannerInputCount; i < end; i++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited(_visit) &&
!visit(spanner, glm::vec3(), 0.0f)) {
if (spanner->testAndSetVisited(_visit) && !visit(spanner)) {
return SHORT_CIRCUIT;
}
}
}
if (!info.isLeaf) {
return _order;
}
for (int i = _inputs.size() - _spannerMaskCount; i < _inputs.size(); i++) {
float maskValue = info.inputValues.at(i).getInlineValue<float>();
if (maskValue < 0.5f) {
const MetavoxelInfo* nextInfo = &info;
do {
foreach (const SharedObjectPointer& object, nextInfo->inputValues.at(
i - _spannerInputCount).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->isMasked() && !visit(spanner, info.minimum, info.size)) {
return SHORT_CIRCUIT;
}
}
} while ((nextInfo = nextInfo->parentInfo));
}
}
return STOP_RECURSION;
return info.isLeaf ? STOP_RECURSION : _order;
}
RayIntersectionVisitor::RayIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
@ -1429,11 +1405,10 @@ int RayIntersectionVisitor::visit(MetavoxelInfo& info) {
}
RaySpannerIntersectionVisitor::RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& spannerMasks,
const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
RayIntersectionVisitor(origin, direction, inputs + spannerInputs + spannerMasks, outputs, lod),
_spannerInputCount(spannerInputs.size()),
_spannerMaskCount(spannerMasks.size()) {
const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
RayIntersectionVisitor(origin, direction, inputs + spannerInputs, outputs, lod),
_spannerInputCount(spannerInputs.size()) {
}
void RaySpannerIntersectionVisitor::prepare(MetavoxelData* data) {
@ -1453,12 +1428,12 @@ bool operator<(const SpannerDistance& first, const SpannerDistance& second) {
int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
QVarLengthArray<SpannerDistance, 4> spannerDistances;
for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) {
for (int end = _inputs.size(), i = end - _spannerInputCount; i < end; i++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited(_visit)) {
if (spanner->testAndSetVisited(_visit)) {
SpannerDistance spannerDistance = { spanner };
if (spanner->findRayIntersection(_origin, _direction, glm::vec3(), 0.0f, spannerDistance.distance)) {
if (spanner->findRayIntersection(_origin, _direction, spannerDistance.distance)) {
spannerDistances.append(spannerDistance);
}
}
@ -1470,36 +1445,7 @@ int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
}
}
}
if (!info.isLeaf) {
return _order;
}
for (int i = _inputs.size() - _spannerMaskCount; i < _inputs.size(); i++) {
float maskValue = info.inputValues.at(i).getInlineValue<float>();
if (maskValue < 0.5f) {
const MetavoxelInfo* nextInfo = &info;
do {
foreach (const SharedObjectPointer& object, nextInfo->inputValues.at(
i - _spannerInputCount).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->isMasked()) {
SpannerDistance spannerDistance = { spanner };
if (spanner->findRayIntersection(_origin, _direction,
info.minimum, info.size, spannerDistance.distance)) {
spannerDistances.append(spannerDistance);
}
}
}
} while ((nextInfo = nextInfo->parentInfo));
qStableSort(spannerDistances);
foreach (const SpannerDistance& spannerDistance, spannerDistances) {
if (!visitSpanner(spannerDistance.spanner, spannerDistance.distance)) {
return SHORT_CIRCUIT;
}
}
}
}
return STOP_RECURSION;
return info.isLeaf ? STOP_RECURSION : _order;
}
bool MetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) {
@ -1765,143 +1711,6 @@ bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) {
return true;
}
ThrobbingMetavoxelGuide::ThrobbingMetavoxelGuide() : _rate(10.0) {
}
bool ThrobbingMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
AttributePointer colorAttribute = AttributeRegistry::getInstance()->getColorAttribute();
for (int i = 0; i < visitation.info.inputValues.size(); i++) {
AttributeValue& attributeValue = visitation.info.inputValues[i];
if (attributeValue.getAttribute() == colorAttribute) {
QRgb base = attributeValue.getInlineValue<QRgb>();
double seconds = QDateTime::currentMSecsSinceEpoch() / 1000.0;
double amplitude = sin(_rate * seconds) * 0.5 + 0.5;
attributeValue.setInlineValue<QRgb>(qRgba(qRed(base) * amplitude, qGreen(base) * amplitude,
qBlue(base) * amplitude, qAlpha(base)));
}
}
return DefaultMetavoxelGuide::guide(visitation);
}
static QScriptValue getAttributes(QScriptEngine* engine, ScriptedMetavoxelGuide* guide,
const QVector<AttributePointer>& attributes) {
QScriptValue attributesValue = engine->newArray(attributes.size());
for (int i = 0; i < attributes.size(); i++) {
attributesValue.setProperty(i, engine->newQObject(attributes.at(i).data(), QScriptEngine::QtOwnership,
QScriptEngine::PreferExistingWrapperObject));
}
return attributesValue;
}
QScriptValue ScriptedMetavoxelGuide::getInputs(QScriptContext* context, QScriptEngine* engine) {
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
return getAttributes(engine, guide, guide->_visitation->visitor->getInputs());
}
QScriptValue ScriptedMetavoxelGuide::getOutputs(QScriptContext* context, QScriptEngine* engine) {
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
return getAttributes(engine, guide, guide->_visitation->visitor->getOutputs());
}
QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngine* engine) {
ScriptedMetavoxelGuide* guide = static_cast<ScriptedMetavoxelGuide*>(context->callee().data().toVariant().value<void*>());
// start with the basics, including inherited attribute values
QScriptValue infoValue = context->argument(0);
QScriptValue minimum = infoValue.property(guide->_minimumHandle);
MetavoxelInfo info(NULL, 0, 0);
info.inputValues = guide->_visitation->info.inputValues;
info.outputValues = guide->_visitation->info.outputValues;
info.minimum = glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber());
info.size = (float)infoValue.property(guide->_sizeHandle).toNumber();
info.isLeaf = infoValue.property(guide->_isLeafHandle).toBool();
// extract and convert the values provided by the script
QScriptValue inputValues = infoValue.property(guide->_inputValuesHandle);
const QVector<AttributePointer>& inputs = guide->_visitation->visitor->getInputs();
for (int i = 0; i < inputs.size(); i++) {
QScriptValue attributeValue = inputValues.property(i);
if (attributeValue.isValid()) {
info.inputValues[i] = AttributeValue(inputs.at(i),
inputs.at(i)->createFromScript(attributeValue, engine));
}
}
QScriptValue result = guide->_visitation->visitor->visit(info);
// destroy any created values
for (int i = 0; i < inputs.size(); i++) {
if (inputValues.property(i).isValid()) {
info.inputValues[i].getAttribute()->destroy(info.inputValues[i].getValue());
}
}
return result;
}
ScriptedMetavoxelGuide::ScriptedMetavoxelGuide() {
}
bool ScriptedMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
QScriptValue guideFunction;
if (_guideFunction) {
guideFunction = _guideFunction->getValue();
} else if (_url.isValid()) {
_guideFunction = ScriptCache::getInstance()->getValue(_url);
guideFunction = _guideFunction->getValue();
}
if (!guideFunction.isValid()) {
// before we load, just use the default behavior
return DefaultMetavoxelGuide::guide(visitation);
}
QScriptEngine* engine = guideFunction.engine();
if (!_minimumHandle.isValid()) {
_minimumHandle = engine->toStringHandle("minimum");
_sizeHandle = engine->toStringHandle("size");
_inputValuesHandle = engine->toStringHandle("inputValues");
_outputValuesHandle = engine->toStringHandle("outputValues");
_isLeafHandle = engine->toStringHandle("isLeaf");
_getInputsFunction = engine->newFunction(getInputs, 0);
_getOutputsFunction = engine->newFunction(getOutputs, 0);
_visitFunction = engine->newFunction(visit, 1);
_info = engine->newObject();
_minimum = engine->newArray(3);
_arguments.clear();
_arguments.append(engine->newObject());
QScriptValue visitor = engine->newObject();
visitor.setProperty("getInputs", _getInputsFunction);
visitor.setProperty("getOutputs", _getOutputsFunction);
visitor.setProperty("visit", _visitFunction);
_arguments[0].setProperty("visitor", visitor);
_arguments[0].setProperty("info", _info);
_info.setProperty(_minimumHandle, _minimum);
}
QScriptValue data = engine->newVariant(QVariant::fromValue<void*>(this));
_getInputsFunction.setData(data);
_visitFunction.setData(data);
_minimum.setProperty(0, visitation.info.minimum.x);
_minimum.setProperty(1, visitation.info.minimum.y);
_minimum.setProperty(2, visitation.info.minimum.z);
_info.setProperty(_sizeHandle, visitation.info.size);
_info.setProperty(_isLeafHandle, visitation.info.isLeaf);
_visitation = &visitation;
guideFunction.call(QScriptValue(), _arguments);
if (engine->hasUncaughtException()) {
qDebug() << "Script error: " << engine->uncaughtException().toString();
}
return true;
}
void ScriptedMetavoxelGuide::setURL(const ParameterizedURL& url) {
_url = url;
_guideFunction.reset();
_minimumHandle = QScriptString();
}
MetavoxelVisitation::MetavoxelVisitation(MetavoxelVisitation* previous,
MetavoxelVisitor* visitor, int inputNodesSize, int outputNodesSize) :
previous(previous),
@ -1997,8 +1806,7 @@ const float DEFAULT_VOXELIZATION_GRANULARITY = powf(2.0f, -3.0f);
Spanner::Spanner() :
_renderer(NULL),
_placementGranularity(DEFAULT_PLACEMENT_GRANULARITY),
_voxelizationGranularity(DEFAULT_VOXELIZATION_GRANULARITY),
_masked(false) {
_voxelizationGranularity(DEFAULT_VOXELIZATION_GRANULARITY) {
}
void Spanner::setBounds(const Box& bounds) {
@ -2009,24 +1817,6 @@ void Spanner::setBounds(const Box& bounds) {
emit boundsChanged(_bounds = bounds);
}
const QVector<AttributePointer>& Spanner::getAttributes() const {
static QVector<AttributePointer> emptyVector;
return emptyVector;
}
const QVector<AttributePointer>& Spanner::getVoxelizedAttributes() const {
static QVector<AttributePointer> emptyVector;
return emptyVector;
}
bool Spanner::getAttributeValues(MetavoxelInfo& info, bool force) const {
return false;
}
bool Spanner::blendAttributeValues(MetavoxelInfo& info, bool force) const {
return false;
}
bool Spanner::testAndSetVisited(int visit) {
QMutexLocker locker(&_lastVisitsMutex);
int& lastVisit = _lastVisits[QThread::currentThread()];
@ -2052,8 +1842,7 @@ SpannerRenderer* Spanner::getRenderer() {
return _renderer;
}
bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
return _bounds.findRayIntersection(origin, direction, distance);
}
@ -2103,12 +1892,11 @@ void SpannerRenderer::simulate(float deltaTime) {
// nothing by default
}
void SpannerRenderer::render(const glm::vec4& color, Mode mode, const glm::vec3& clipMinimum, float clipSize) {
void SpannerRenderer::render(const glm::vec4& color, Mode mode) {
// nothing by default
}
bool SpannerRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
bool SpannerRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
return false;
}
@ -2149,92 +1937,7 @@ Sphere::Sphere() {
updateBounds();
}
const QVector<AttributePointer>& Sphere::getAttributes() const {
static QVector<AttributePointer> attributes = QVector<AttributePointer>() <<
AttributeRegistry::getInstance()->getColorAttribute() << AttributeRegistry::getInstance()->getNormalAttribute();
return attributes;
}
const QVector<AttributePointer>& Sphere::getVoxelizedAttributes() const {
static QVector<AttributePointer> attributes = QVector<AttributePointer>() <<
AttributeRegistry::getInstance()->getSpannerColorAttribute() <<
AttributeRegistry::getInstance()->getSpannerNormalAttribute();
return attributes;
}
bool Sphere::getAttributeValues(MetavoxelInfo& info, bool force) const {
// bounds check
Box bounds = info.getBounds();
if (!(force || getBounds().intersects(bounds))) {
return false;
}
// count the points inside the sphere
int pointsWithin = 0;
for (int i = 0; i < Box::VERTEX_COUNT; i++) {
if (glm::distance(bounds.getVertex(i), getTranslation()) <= getScale()) {
pointsWithin++;
}
}
if (pointsWithin == Box::VERTEX_COUNT) {
// entirely contained
info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline<QRgb>(_color.rgba()));
info.outputValues[1] = getNormal(info, _color.alpha());
return false;
}
if (force || info.size <= getVoxelizationGranularity()) {
// best guess
if (pointsWithin > 0) {
int alpha = _color.alpha() * pointsWithin / Box::VERTEX_COUNT;
info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline<QRgb>(qRgba(
_color.red(), _color.green(), _color.blue(), alpha)));
info.outputValues[1] = getNormal(info, alpha);
}
return false;
}
return true;
}
bool Sphere::blendAttributeValues(MetavoxelInfo& info, bool force) const {
// bounds check
Box bounds = info.getBounds();
if (!(force || getBounds().intersects(bounds))) {
return false;
}
// count the points inside the sphere
int pointsWithin = 0;
for (int i = 0; i < Box::VERTEX_COUNT; i++) {
if (glm::distance(bounds.getVertex(i), getTranslation()) <= getScale()) {
pointsWithin++;
}
}
if (pointsWithin == Box::VERTEX_COUNT) {
// entirely contained
info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline<QRgb>(_color.rgba()));
info.outputValues[1] = getNormal(info, _color.alpha());
return false;
}
if (force || info.size <= getVoxelizationGranularity()) {
// best guess
if (pointsWithin > 0) {
const AttributeValue& oldColor = info.outputValues.at(0).getAttribute() ?
info.outputValues.at(0) : info.inputValues.at(0);
const AttributeValue& oldNormal = info.outputValues.at(1).getAttribute() ?
info.outputValues.at(1) : info.inputValues.at(1);
int oldAlpha = qAlpha(oldColor.getInlineValue<QRgb>());
int newAlpha = _color.alpha() * pointsWithin / Box::VERTEX_COUNT;
float combinedAlpha = (float)newAlpha / (oldAlpha + newAlpha);
int baseAlpha = _color.alpha() * pointsWithin / Box::VERTEX_COUNT;
info.outputValues[0].mix(oldColor, AttributeValue(getAttributes().at(0),
encodeInline<QRgb>(qRgba(_color.red(), _color.green(), _color.blue(), baseAlpha))), combinedAlpha);
info.outputValues[1].mix(oldNormal, getNormal(info, baseAlpha), combinedAlpha);
}
return false;
}
return true;
}
bool Sphere::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
bool Sphere::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
return findRaySphereIntersection(origin, direction, getTranslation(), getScale(), distance);
}
@ -2279,23 +1982,6 @@ void Sphere::updateBounds() {
setBounds(Box(getTranslation() - extent, getTranslation() + extent));
}
AttributeValue Sphere::getNormal(MetavoxelInfo& info, int alpha) const {
glm::vec3 normal = info.getCenter() - getTranslation();
float length = glm::length(normal);
QRgb color;
if (alpha != 0 && length > EPSILON) {
const float NORMAL_SCALE = 127.0f;
float scale = NORMAL_SCALE / length;
const int BYTE_MASK = 0xFF;
color = qRgba((int)(normal.x * scale) & BYTE_MASK, (int)(normal.y * scale) & BYTE_MASK,
(int)(normal.z * scale) & BYTE_MASK, alpha);
} else {
color = QRgb();
}
return AttributeValue(getAttributes().at(1), encodeInline<QRgb>(color));
}
Cuboid::Cuboid() :
_aspectY(1.0f),
_aspectZ(1.0f) {
@ -2388,11 +2074,10 @@ void StaticModel::setURL(const QUrl& url) {
}
}
bool StaticModel::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
bool StaticModel::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
// delegate to renderer, if we have one
return _renderer ? _renderer->findRayIntersection(origin, direction, clipMinimum, clipSize, distance) :
Spanner::findRayIntersection(origin, direction, clipMinimum, clipSize, distance);
return _renderer ? _renderer->findRayIntersection(origin, direction, distance) :
Spanner::findRayIntersection(origin, direction, distance);
}
QByteArray StaticModel::getRendererClassName() const {

View file

@ -12,13 +12,10 @@
#ifndef hifi_MetavoxelData_h
#define hifi_MetavoxelData_h
#include <QBitArray>
#include <QHash>
#include <QMutex>
#include <QSharedData>
#include <QSharedPointer>
#include <QScriptString>
#include <QScriptValue>
#include <QVector>
#include <glm/glm.hpp>
@ -26,8 +23,6 @@
#include "AttributeRegistry.h"
#include "MetavoxelUtil.h"
class QScriptContext;
class MetavoxelInfo;
class MetavoxelNode;
class MetavoxelRendererImplementation;
@ -373,16 +368,14 @@ class SpannerVisitor : public MetavoxelVisitor {
public:
SpannerVisitor(const QVector<AttributePointer>& spannerInputs,
const QVector<AttributePointer>& spannerMasks = QVector<AttributePointer>(),
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD(),
int order = DEFAULT_ORDER);
/// Visits a spanner (or part thereof).
/// \param clipSize the size of the clip volume, or zero if unclipped
/// Visits a spanner.
/// \return true to continue, false to short-circuit the tour
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) = 0;
virtual bool visit(Spanner* spanner) = 0;
virtual void prepare(MetavoxelData* data);
virtual int visit(MetavoxelInfo& info);
@ -390,7 +383,6 @@ public:
protected:
int _spannerInputCount;
int _spannerMaskCount;
int _order;
int _visit;
};
@ -422,12 +414,11 @@ public:
RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& spannerInputs,
const QVector<AttributePointer>& spannerMasks = QVector<AttributePointer>(),
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());
/// Visits a spannerthat the ray intersects.
/// Visits a spanner that the ray intersects.
/// \return true to continue, false to short-circuit the tour
virtual bool visitSpanner(Spanner* spanner, float distance) = 0;
@ -437,7 +428,6 @@ public:
protected:
int _spannerInputCount;
int _spannerMaskCount;
int _visit;
};
@ -468,62 +458,6 @@ public:
virtual bool guideToDifferent(MetavoxelVisitation& visitation);
};
/// A temporary test guide that just makes the existing voxels throb with delight.
class ThrobbingMetavoxelGuide : public DefaultMetavoxelGuide {
Q_OBJECT
Q_PROPERTY(float rate MEMBER _rate)
public:
Q_INVOKABLE ThrobbingMetavoxelGuide();
virtual bool guide(MetavoxelVisitation& visitation);
private:
float _rate;
};
/// Represents a guide implemented in Javascript.
class ScriptedMetavoxelGuide : public DefaultMetavoxelGuide {
Q_OBJECT
Q_PROPERTY(ParameterizedURL url MEMBER _url WRITE setURL)
public:
Q_INVOKABLE ScriptedMetavoxelGuide();
virtual bool guide(MetavoxelVisitation& visitation);
public slots:
void setURL(const ParameterizedURL& url);
private:
static QScriptValue getInputs(QScriptContext* context, QScriptEngine* engine);
static QScriptValue getOutputs(QScriptContext* context, QScriptEngine* engine);
static QScriptValue visit(QScriptContext* context, QScriptEngine* engine);
ParameterizedURL _url;
QSharedPointer<NetworkValue> _guideFunction;
QScriptString _minimumHandle;
QScriptString _sizeHandle;
QScriptString _inputValuesHandle;
QScriptString _outputValuesHandle;
QScriptString _isLeafHandle;
QScriptValueList _arguments;
QScriptValue _getInputsFunction;
QScriptValue _getOutputsFunction;
QScriptValue _visitFunction;
QScriptValue _info;
QScriptValue _minimum;
MetavoxelVisitation* _visitation;
};
/// Contains the state associated with a visit to a metavoxel system.
class MetavoxelVisitation {
public:
@ -598,7 +532,6 @@ class Spanner : public SharedObject {
Q_PROPERTY(Box bounds MEMBER _bounds WRITE setBounds NOTIFY boundsChanged DESIGNABLE false)
Q_PROPERTY(float placementGranularity MEMBER _placementGranularity DESIGNABLE false)
Q_PROPERTY(float voxelizationGranularity MEMBER _voxelizationGranularity DESIGNABLE false)
Q_PROPERTY(float masked MEMBER _masked DESIGNABLE false)
public:
@ -616,24 +549,6 @@ public:
void setVoxelizationGranularity(float granularity) { _voxelizationGranularity = granularity; }
float getVoxelizationGranularity() const { return _voxelizationGranularity; }
void setMasked(bool masked) { _masked = masked; }
bool isMasked() const { return _masked; }
/// Returns a reference to the list of attributes associated with this spanner.
virtual const QVector<AttributePointer>& getAttributes() const;
/// Returns a reference to the list of corresponding attributes that we voxelize the spanner into.
virtual const QVector<AttributePointer>& getVoxelizedAttributes() const;
/// Sets the attribute values associated with this spanner in the supplied info.
/// \return true to recurse, false to stop
virtual bool getAttributeValues(MetavoxelInfo& info, bool force = false) const;
/// Blends the attribute values associated with this spanner into the supplied info.
/// \param force if true, blend even if we would normally subdivide
/// \return true to recurse, false to stop
virtual bool blendAttributeValues(MetavoxelInfo& info, bool force = false) const;
/// Checks whether we've visited this object on the current traversal. If we have, returns false.
/// If we haven't, sets the last visit identifier and returns true.
bool testAndSetVisited(int visit);
@ -642,9 +557,7 @@ public:
SpannerRenderer* getRenderer();
/// Finds the intersection between the described ray and this spanner.
/// \param clipSize the size of the clip region, or zero if unclipped
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
/// Checks whether this spanner has its own colors.
virtual bool hasOwnColors() const;
@ -684,7 +597,6 @@ private:
Box _bounds;
float _placementGranularity;
float _voxelizationGranularity;
bool _masked;
QHash<QThread*, int> _lastVisits; ///< last visit identifiers for each thread
QMutex _lastVisitsMutex;
@ -703,9 +615,8 @@ public:
virtual void init(Spanner* spanner);
virtual void simulate(float deltaTime);
virtual void render(const glm::vec4& color, Mode mode, const glm::vec3& clipMinimum, float clipSize);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
virtual void render(const glm::vec4& color, Mode mode);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
protected:
@ -774,12 +685,7 @@ public:
Q_INVOKABLE Sphere();
virtual const QVector<AttributePointer>& getAttributes() const;
virtual const QVector<AttributePointer>& getVoxelizedAttributes() const;
virtual bool getAttributeValues(MetavoxelInfo& info, bool force = false) const;
virtual bool blendAttributeValues(MetavoxelInfo& info, bool force = false) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
virtual bool contains(const glm::vec3& point);
virtual bool intersects(const glm::vec3& start, const glm::vec3& end, float& distance, glm::vec3& normal);
@ -790,10 +696,6 @@ protected:
private slots:
void updateBounds();
private:
AttributeValue getNormal(MetavoxelInfo& info, int alpha) const;
};
/// A cuboid.
@ -849,8 +751,7 @@ public:
void setURL(const QUrl& url);
const QUrl& getURL() const { return _url; }
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
signals:

View file

@ -39,8 +39,7 @@ private:
};
BoxSetEditVisitor::BoxSetEditVisitor(const BoxSetEdit& edit) :
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute() <<
AttributeRegistry::getInstance()->getSpannerMaskAttribute()),
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute()),
_edit(edit) {
}
@ -55,57 +54,17 @@ int BoxSetEditVisitor::visit(MetavoxelInfo& info) {
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
if (volume >= 1.0f) {
info.outputValues[0] = _edit.value;
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<float>(1.0f));
return STOP_RECURSION; // entirely contained
}
if (info.size <= _edit.granularity) {
if (volume >= 0.5f) {
info.outputValues[0] = _edit.value;
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<float>(1.0f));
}
return STOP_RECURSION; // reached granularity limit; take best guess
}
return DEFAULT_ORDER; // subdivide
}
class GatherUnmaskedSpannersVisitor : public SpannerVisitor {
public:
GatherUnmaskedSpannersVisitor(const Box& bounds);
const QList<SharedObjectPointer>& getUnmaskedSpanners() const { return _unmaskedSpanners; }
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
private:
Box _bounds;
QList<SharedObjectPointer> _unmaskedSpanners;
};
GatherUnmaskedSpannersVisitor::GatherUnmaskedSpannersVisitor(const Box& bounds) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()),
_bounds(bounds) {
}
bool GatherUnmaskedSpannersVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
if (!spanner->isMasked() && spanner->getBounds().intersects(_bounds)) {
_unmaskedSpanners.append(spanner);
}
return true;
}
static void setIntersectingMasked(const Box& bounds, MetavoxelData& data) {
GatherUnmaskedSpannersVisitor visitor(bounds);
data.guide(visitor);
foreach (const SharedObjectPointer& object, visitor.getUnmaskedSpanners()) {
Spanner* newSpanner = static_cast<Spanner*>(object->clone(true));
newSpanner->setMasked(true);
data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), object, newSpanner);
}
}
void BoxSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
// expand to fit the entire edit
while (!data.getBounds().contains(region)) {
@ -114,9 +73,6 @@ void BoxSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects)
BoxSetEditVisitor setVisitor(*this);
data.guide(setVisitor);
// flip the mask flag of all intersecting spanners
setIntersectingMasked(region, data);
}
GlobalSetEdit::GlobalSetEdit(const OwnedAttributeValue& value) :
@ -155,56 +111,8 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh
spanner(spanner) {
}
class UpdateSpannerVisitor : public MetavoxelVisitor {
public:
UpdateSpannerVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner);
virtual int visit(MetavoxelInfo& info);
private:
Spanner* _spanner;
float _voxelizationSize;
int _steps;
};
UpdateSpannerVisitor::UpdateSpannerVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) :
MetavoxelVisitor(QVector<AttributePointer>() << attributes << AttributeRegistry::getInstance()->getSpannersAttribute(),
attributes),
_spanner(spanner),
_voxelizationSize(qMax(spanner->getBounds().getLongestSide(), spanner->getPlacementGranularity()) * 2.0f /
AttributeRegistry::getInstance()->getSpannersAttribute()->getLODThresholdMultiplier()),
_steps(glm::round(logf(AttributeRegistry::getInstance()->getSpannersAttribute()->getLODThresholdMultiplier()) /
logf(2.0f) - 2.0f)) {
}
int UpdateSpannerVisitor::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_spanner->getBounds())) {
return STOP_RECURSION;
}
MetavoxelInfo* parentInfo = info.parentInfo;
for (int i = 0; i < _steps && parentInfo; i++) {
parentInfo = parentInfo->parentInfo;
}
for (int i = 0; i < _outputs.size(); i++) {
info.outputValues[i] = AttributeValue(_outputs.at(i));
}
if (parentInfo) {
foreach (const SharedObjectPointer& object,
parentInfo->inputValues.at(_outputs.size()).getInlineValue<SharedObjectSet>()) {
static_cast<const Spanner*>(object.data())->blendAttributeValues(info, true);
}
}
return (info.size > _voxelizationSize) ? DEFAULT_ORDER : STOP_RECURSION;
}
void InsertSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
data.insert(attribute, this->spanner);
Spanner* spanner = static_cast<Spanner*>(this->spanner.data());
UpdateSpannerVisitor visitor(spanner->getVoxelizedAttributes(), spanner);
data.guide(visitor);
data.insert(attribute, spanner);
}
RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) :
@ -218,99 +126,15 @@ void RemoveSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& o
qDebug() << "Missing object to remove" << id;
return;
}
// keep a strong reference to the object
SharedObjectPointer sharedPointer = object;
data.remove(attribute, object);
Spanner* spanner = static_cast<Spanner*>(object);
UpdateSpannerVisitor visitor(spanner->getVoxelizedAttributes(), spanner);
data.guide(visitor);
}
ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) :
attribute(attribute) {
}
class GatherSpannerAttributesVisitor : public SpannerVisitor {
public:
GatherSpannerAttributesVisitor(const AttributePointer& attribute);
const QSet<AttributePointer>& getAttributes() const { return _attributes; }
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
protected:
QSet<AttributePointer> _attributes;
};
GatherSpannerAttributesVisitor::GatherSpannerAttributesVisitor(const AttributePointer& attribute) :
SpannerVisitor(QVector<AttributePointer>() << attribute) {
}
bool GatherSpannerAttributesVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
foreach (const AttributePointer& attribute, spanner->getVoxelizedAttributes()) {
_attributes.insert(attribute);
}
return true;
}
void ClearSpannersEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
// find all the spanner attributes
GatherSpannerAttributesVisitor visitor(attribute);
data.guide(visitor);
data.clear(attribute);
foreach (const AttributePointer& attribute, visitor.getAttributes()) {
data.clear(attribute);
}
}
SetSpannerEdit::SetSpannerEdit(const SharedObjectPointer& spanner) :
spanner(spanner) {
}
class SetSpannerEditVisitor : public MetavoxelVisitor {
public:
SetSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner);
virtual int visit(MetavoxelInfo& info);
private:
Spanner* _spanner;
};
SetSpannerEditVisitor::SetSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) :
MetavoxelVisitor(attributes, QVector<AttributePointer>() << attributes <<
AttributeRegistry::getInstance()->getSpannerMaskAttribute()),
_spanner(spanner) {
}
int SetSpannerEditVisitor::visit(MetavoxelInfo& info) {
if (_spanner->blendAttributeValues(info)) {
return DEFAULT_ORDER;
}
if (info.outputValues.at(0).getAttribute()) {
info.outputValues.last() = AttributeValue(_outputs.last(), encodeInline<float>(1.0f));
}
return STOP_RECURSION;
}
void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
Spanner* spanner = static_cast<Spanner*>(this->spanner.data());
// expand to fit the entire spanner
while (!data.getBounds().contains(spanner->getBounds())) {
data.expand();
}
SetSpannerEditVisitor visitor(spanner->getAttributes(), spanner);
data.guide(visitor);
setIntersectingMasked(spanner->getBounds(), data);
}
SetDataEdit::SetDataEdit(const glm::vec3& minimum, const MetavoxelData& data, bool blend) :

View file

@ -177,21 +177,6 @@ public:
DECLARE_STREAMABLE_METATYPE(ClearSpannersEdit)
/// An edit that sets a spanner's attributes in the voxel tree.
class SetSpannerEdit : public MetavoxelEdit {
STREAMABLE
public:
STREAM SharedObjectPointer spanner;
SetSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer());
virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const;
};
DECLARE_STREAMABLE_METATYPE(SetSpannerEdit)
/// An edit that directly sets part of the metavoxel data.
class SetDataEdit : public MetavoxelEdit {
STREAMABLE

View file

@ -439,12 +439,17 @@ static bool testSerialization(Bitstream::MetadataType metadataType) {
return false;
}
static AttributePointer simpleAttribute;
bool MetavoxelTests::run() {
LimitedNodeList::createInstance();
// seed the random number generator so that our tests are reproducible
srand(0xBAAAAABE);
// register our test attribute
simpleAttribute = AttributeRegistry::getInstance()->registerAttribute(new FloatAttribute("simpleAttribute"));
// check for an optional command line argument specifying a single test
QStringList arguments = this->arguments();
int test = (arguments.size() > 1) ? arguments.at(1).toInt() : 0;
@ -582,8 +587,7 @@ public:
};
RandomVisitor::RandomVisitor() :
MetavoxelVisitor(QVector<AttributePointer>(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute()),
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << simpleAttribute),
leafCount(0) {
}
@ -594,8 +598,7 @@ int RandomVisitor::visit(MetavoxelInfo& info) {
if (info.size > MAXIMUM_LEAF_SIZE || (info.size > MINIMUM_LEAF_SIZE && randomBoolean())) {
return DEFAULT_ORDER;
}
info.outputValues[0] = OwnedAttributeValue(_outputs.at(0), encodeInline<QRgb>(qRgb(randomColorValue(),
randomColorValue(), randomColorValue())));
info.outputValues[0] = OwnedAttributeValue(_outputs.at(0), encodeInline<float>(randFloat()));
leafCount++;
return STOP_RECURSION;
}
@ -812,8 +815,7 @@ private:
};
MutateVisitor::MutateVisitor() :
MetavoxelVisitor(QVector<AttributePointer>(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute()),
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << simpleAttribute),
_mutationsRemaining(randIntInRange(2, 4)) {
}
@ -824,8 +826,7 @@ int MutateVisitor::visit(MetavoxelInfo& info) {
if (info.size > MAXIMUM_LEAF_SIZE || (info.size > MINIMUM_LEAF_SIZE && randomBoolean())) {
return encodeRandomOrder();
}
info.outputValues[0] = OwnedAttributeValue(_outputs.at(0), encodeInline<QRgb>(qRgb(randomColorValue(),
randomColorValue(), randomColorValue())));
info.outputValues[0] = OwnedAttributeValue(_outputs.at(0), encodeInline<float>(randFloat()));
_mutationsRemaining--;
metavoxelMutationsPerformed++;
return STOP_RECURSION;