diff --git a/examples/metavoxels.js b/examples/metavoxels.js new file mode 100644 index 0000000000..32177cdcba --- /dev/null +++ b/examples/metavoxels.js @@ -0,0 +1,41 @@ +// +// metavoxels.js +// examples +// +// Copyright 2014 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 +// + +Script.setInterval(function() { + var spanner; + if (Math.random() < 0.5) { + spanner = new Sphere(); + } else { + spanner = new Cuboid(); + spanner.aspectX = 0.1 + Math.random() * 1.9; + spanner.aspectY = 0.1 + Math.random() * 1.9; + } + spanner.scale = 0.1 + Math.random() * 1.9; + spanner.rotation = Quat.fromPitchYawRollDegrees(Math.random() * 360.0, Math.random() * 360.0, Math.random() * 360.0); + spanner.translation = { x: 10.0 + Math.random() * 10.0, y: 10.0 + Math.random() * 10.0, z: 10.0 + Math.random() * 10.0 }; + + if (Math.random() < 0.5) { + var material = new MaterialObject(); + if (Math.random() < 0.5) { + material.diffuse = "http://www.fungibleinsight.com/faces/grass.jpg"; + } else { + material.diffuse = "http://www.fungibleinsight.com/faces/soil.jpg"; + } + Metavoxels.setVoxelMaterial(spanner, material); + + } else if (Math.random() < 0.5) { + Metavoxels.setVoxelColor(spanner, { red: Math.random() * 255.0, green: Math.random() * 255.0, + blue: Math.random() * 255.0 }); + + } else { + Metavoxels.setVoxelColor(spanner, { red: 0, green: 0, blue: 0, alpha: 0 }); + } +}, 1000); + diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 24a1026ef4..8ed00be93b 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -23,6 +23,7 @@ #include +#include #include #include @@ -454,6 +455,36 @@ float MetavoxelSystem::getHeightfieldHeight(const glm::vec3& location) { return visitor.height; } +void MetavoxelSystem::paintHeightfieldColor(const glm::vec3& position, float radius, const QColor& color) { + MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldMaterialEdit(position, radius, SharedObjectPointer(), color)) }; + applyEdit(edit, true); +} + +void MetavoxelSystem::paintHeightfieldMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material) { + MetavoxelEditMessage edit = { QVariant::fromValue(PaintHeightfieldMaterialEdit(position, radius, material)) }; + applyMaterialEdit(edit, true); +} + +void MetavoxelSystem::paintVoxelColor(const glm::vec3& position, float radius, const QColor& color) { + MetavoxelEditMessage edit = { QVariant::fromValue(PaintVoxelMaterialEdit(position, radius, SharedObjectPointer(), color)) }; + applyEdit(edit, true); +} + +void MetavoxelSystem::paintVoxelMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material) { + MetavoxelEditMessage edit = { QVariant::fromValue(PaintVoxelMaterialEdit(position, radius, material)) }; + applyMaterialEdit(edit, true); +} + +void MetavoxelSystem::setVoxelColor(const SharedObjectPointer& spanner, const QColor& color) { + MetavoxelEditMessage edit = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, SharedObjectPointer(), color)) }; + applyEdit(edit, true); +} + +void MetavoxelSystem::setVoxelMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material) { + MetavoxelEditMessage edit = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material)) }; + applyMaterialEdit(edit, true); +} + class CursorRenderVisitor : public MetavoxelVisitor { public: @@ -563,6 +594,55 @@ void MetavoxelSystem::deleteTextures(int heightID, int colorID, int textureID) { glDeleteTextures(1, (GLuint*)&textureID); } +class MaterialEditApplier : public SignalHandler { +public: + + MaterialEditApplier(const MetavoxelEditMessage& message, const QSharedPointer texture); + + virtual void handle(); + +protected: + + MetavoxelEditMessage _message; + QSharedPointer _texture; +}; + +MaterialEditApplier::MaterialEditApplier(const MetavoxelEditMessage& message, const QSharedPointer texture) : + _message(message), + _texture(texture) { +} + +void MaterialEditApplier::handle() { + static_cast(_message.edit.data())->averageColor = _texture->getAverageColor(); + Application::getInstance()->getMetavoxels()->applyEdit(_message, true); + deleteLater(); +} + +void MetavoxelSystem::applyMaterialEdit(const MetavoxelEditMessage& message, bool reliable) { + const MaterialEdit* edit = static_cast(message.edit.constData()); + MaterialObject* material = static_cast(edit->material.data()); + if (material && material->getDiffuse().isValid()) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "applyMaterialEdit", Q_ARG(const MetavoxelEditMessage&, message), + Q_ARG(bool, reliable)); + return; + } + QSharedPointer texture = Application::getInstance()->getTextureCache()->getTexture( + material->getDiffuse(), SPLAT_TEXTURE); + if (texture->isLoaded()) { + MetavoxelEditMessage newMessage = message; + static_cast(newMessage.edit.data())->averageColor = texture->getAverageColor(); + applyEdit(newMessage, true); + + } else { + MaterialEditApplier* applier = new MaterialEditApplier(message, texture); + connect(texture.data(), &Resource::loaded, applier, &SignalHandler::handle); + } + } else { + applyEdit(message, true); + } +} + MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) { return new MetavoxelSystemClient(node, _updater); } diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index f479ba5e50..ac6a75c68b 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -54,6 +54,18 @@ public: Q_INVOKABLE float getHeightfieldHeight(const glm::vec3& location); + Q_INVOKABLE void paintHeightfieldColor(const glm::vec3& position, float radius, const QColor& color); + + Q_INVOKABLE void paintHeightfieldMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material); + + Q_INVOKABLE void paintVoxelColor(const glm::vec3& position, float radius, const QColor& color); + + Q_INVOKABLE void paintVoxelMaterial(const glm::vec3& position, float radius, const SharedObjectPointer& material); + + Q_INVOKABLE void setVoxelColor(const SharedObjectPointer& spanner, const QColor& color); + + Q_INVOKABLE void setVoxelMaterial(const SharedObjectPointer& spanner, const SharedObjectPointer& material); + Q_INVOKABLE void deleteTextures(int heightID, int colorID, int textureID); signals: @@ -66,6 +78,8 @@ public slots: protected: + Q_INVOKABLE void applyMaterialEdit(const MetavoxelEditMessage& message, bool reliable = false); + virtual MetavoxelClient* createClient(const SharedNodePointer& node); private: @@ -81,6 +95,15 @@ private: Frustum _frustum; }; +/// Generic abstract base class for objects that handle a signal. +class SignalHandler : public QObject { + Q_OBJECT + +public slots: + + virtual void handle() = 0; +}; + /// Describes contents of a point in a point buffer. class BufferPoint { public: diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index ee7cf63789..b7e650a42d 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1392,16 +1392,14 @@ void VoxelMaterialBoxTool::applyValue(const glm::vec3& minimum, const glm::vec3& } else { material = SharedObjectPointer(); } - QColor color = _color->getColor(); - color.setAlphaF(color.alphaF() > 0.5f ? 1.0f : 0.0f); - Cuboid* cuboid = new Cuboid(); cuboid->setTranslation((maximum + minimum) * 0.5f); glm::vec3 vector = (maximum - minimum) * 0.5f; cuboid->setScale(vector.x); cuboid->setAspectY(vector.y / vector.x); cuboid->setAspectZ(vector.z / vector.x); - MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(SharedObjectPointer(cuboid), material, color)) }; + MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(SharedObjectPointer(cuboid), + material, _color->getColor())) }; Application::getInstance()->getMetavoxels()->applyEdit(message, true); } @@ -1489,9 +1487,7 @@ void VoxelMaterialSpannerTool::applyEdit(const AttributePointer& attribute, cons } else { material = SharedObjectPointer(); } - QColor color = _color->getColor(); - color.setAlphaF(color.alphaF() > 0.5f ? 1.0f : 0.0f); - MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material, color)) }; + MetavoxelEditMessage message = { QVariant::fromValue(VoxelMaterialSpannerEdit(spanner, material, _color->getColor())) }; Application::getInstance()->getMetavoxels()->applyEdit(message, true); } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index a2d3410314..57f7b53cc3 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -74,6 +74,11 @@ void MetavoxelClientManager::setSpanner(const SharedObjectPointer& object, bool 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); +} + void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool reliable) { QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable)); } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index 333b709b9e..7ddee2d68d 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -41,6 +41,8 @@ public: 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); /// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread. diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 29fbe182d3..c83a953f03 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -18,6 +18,10 @@ void MetavoxelEditMessage::apply(MetavoxelData& data, const WeakSharedObjectHash MetavoxelEdit::~MetavoxelEdit() { } +void MetavoxelEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { + // nothing by default +} + BoxSetEdit::BoxSetEdit(const Box& region, float granularity, const OwnedAttributeValue& value) : region(region), granularity(granularity), value(value) { } @@ -408,6 +412,11 @@ void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObje data.guide(visitor); } +MaterialEdit::MaterialEdit(const SharedObjectPointer& material, const QColor& averageColor) : + material(material), + averageColor(averageColor) { +} + class PaintHeightfieldMaterialEditVisitor : public MetavoxelVisitor { public: @@ -595,10 +604,9 @@ int PaintHeightfieldMaterialEditVisitor::visit(MetavoxelInfo& info) { PaintHeightfieldMaterialEdit::PaintHeightfieldMaterialEdit(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& averageColor) : + MaterialEdit(material, averageColor), position(position), - radius(radius), - material(material), - averageColor(averageColor) { + radius(radius) { } void PaintHeightfieldMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { @@ -613,9 +621,8 @@ const int VOXEL_BLOCK_VOLUME = VOXEL_BLOCK_AREA * VOXEL_BLOCK_SAMPLES; VoxelMaterialSpannerEdit::VoxelMaterialSpannerEdit(const SharedObjectPointer& spanner, const SharedObjectPointer& material, const QColor& averageColor) : - spanner(spanner), - material(material), - averageColor(averageColor) { + MaterialEdit(material, averageColor), + spanner(spanner) { } class VoxelMaterialSpannerEditVisitor : public MetavoxelVisitor { @@ -845,16 +852,18 @@ void VoxelMaterialSpannerEdit::apply(MetavoxelData& data, const WeakSharedObject while (!data.getBounds().contains(spanner->getBounds())) { data.expand(); } - VoxelMaterialSpannerEditVisitor visitor(spanner, material, averageColor); + // make sure it's either 100% transparent or 100% opaque + QColor color = averageColor; + color.setAlphaF(color.alphaF() > 0.5f ? 1.0f : 0.0f); + VoxelMaterialSpannerEditVisitor visitor(spanner, material, color); data.guide(visitor); } PaintVoxelMaterialEdit::PaintVoxelMaterialEdit(const glm::vec3& position, float radius, const SharedObjectPointer& material, const QColor& averageColor) : + MaterialEdit(material, averageColor), position(position), - radius(radius), - material(material), - averageColor(averageColor) { + radius(radius) { } class PaintVoxelMaterialEditVisitor : public MetavoxelVisitor { @@ -950,6 +959,9 @@ int PaintVoxelMaterialEditVisitor::visit(MetavoxelInfo& info) { } void PaintVoxelMaterialEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { - PaintVoxelMaterialEditVisitor visitor(position, radius, material, averageColor); + // make sure it's 100% opaque + QColor color = averageColor; + color.setAlphaF(1.0f); + PaintVoxelMaterialEditVisitor visitor(position, radius, material, color); data.guide(visitor); } diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 0ac0bf59ec..9a7e254571 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -91,7 +91,7 @@ public: virtual ~MetavoxelEdit(); - virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const = 0; + virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; }; /// An edit that sets the region within a box to a value. @@ -224,16 +224,28 @@ public: DECLARE_STREAMABLE_METATYPE(PaintHeightfieldHeightEdit) +/// Base class for edits that have materials. +class MaterialEdit : public MetavoxelEdit { + STREAMABLE + +public: + + STREAM SharedObjectPointer material; + STREAM QColor averageColor; + + MaterialEdit(const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor()); +}; + +DECLARE_STREAMABLE_METATYPE(MaterialEdit) + /// An edit that sets a region of a heightfield material. -class PaintHeightfieldMaterialEdit : public MetavoxelEdit { +class PaintHeightfieldMaterialEdit : STREAM public MaterialEdit { STREAMABLE public: STREAM glm::vec3 position; STREAM float radius; - STREAM SharedObjectPointer material; - STREAM QColor averageColor; PaintHeightfieldMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor()); @@ -244,14 +256,12 @@ public: DECLARE_STREAMABLE_METATYPE(PaintHeightfieldMaterialEdit) /// An edit that sets the materials of voxels within a spanner to a value. -class VoxelMaterialSpannerEdit : public MetavoxelEdit { +class VoxelMaterialSpannerEdit : STREAM public MaterialEdit { STREAMABLE public: STREAM SharedObjectPointer spanner; - STREAM SharedObjectPointer material; - STREAM QColor averageColor; VoxelMaterialSpannerEdit(const SharedObjectPointer& spanner = SharedObjectPointer(), const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor()); @@ -262,15 +272,13 @@ public: DECLARE_STREAMABLE_METATYPE(VoxelMaterialSpannerEdit) /// An edit that sets a region of a voxel material. -class PaintVoxelMaterialEdit : public MetavoxelEdit { +class PaintVoxelMaterialEdit : STREAM public MaterialEdit { STREAMABLE public: STREAM glm::vec3 position; STREAM float radius; - STREAM SharedObjectPointer material; - STREAM QColor averageColor; PaintVoxelMaterialEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, const SharedObjectPointer& material = SharedObjectPointer(), const QColor& averageColor = QColor()); diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index eddd63ca7a..e3bfbb8f84 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -85,7 +85,7 @@ PacketVersion versionForPacketType(PacketType type) { case PacketTypeAudioStreamStats: return 1; case PacketTypeMetavoxelData: - return 6; + return 7; case PacketTypeVoxelData: return VERSION_VOXELS_HAS_FILE_BREAKS; default: diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index ec9ef14e3c..7dafde9e43 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -10,6 +10,7 @@ // #include +#include #include #include "RegisteredMetaTypes.h" @@ -29,6 +30,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); qScriptRegisterMetaType(engine, xColorToScriptValue, xColorFromScriptValue); qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); + qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue); qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); @@ -129,6 +131,14 @@ void qColorFromScriptValue(const QScriptValue& object, QColor& color) { } } +QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url) { + return url.toString(); +} + +void qURLFromScriptValue(const QScriptValue& object, QUrl& url) { + url = object.toString(); +} + QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay) { QScriptValue obj = engine->newObject(); QScriptValue origin = vec3toScriptValue(engine, pickRay.origin); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index d3d31752b6..a1c6fdf710 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -20,6 +20,7 @@ #include "SharedUtil.h" class QColor; +class QUrl; Q_DECLARE_METATYPE(glm::vec4) Q_DECLARE_METATYPE(glm::vec3) @@ -47,6 +48,9 @@ void xColorFromScriptValue(const QScriptValue &object, xColor& color); QScriptValue qColorToScriptValue(QScriptEngine* engine, const QColor& color); void qColorFromScriptValue(const QScriptValue& object, QColor& color); +QScriptValue qURLToScriptValue(QScriptEngine* engine, const QUrl& url); +void qURLFromScriptValue(const QScriptValue& object, QUrl& url); + class PickRay { public: PickRay() : origin(0), direction(0) { };