diff --git a/examples/dialTone.js b/examples/dialTone.js
index 0748d0ba94..135acb17f4 100644
--- a/examples/dialTone.js
+++ b/examples/dialTone.js
@@ -14,10 +14,10 @@ var connectSound = SoundCache.getSound("file://" + Paths.resources + "sounds/sho
// setup the options needed for that sound
var connectSoundOptions = {
- localOnly: true
+ localOnly: true
}
// play the sound locally once we get the first audio packet from a mixer
Audio.receivedFirstPacket.connect(function(){
- Audio.playSound(connectSound, connectSoundOptions);
+ Audio.playSound(connectSound, connectSoundOptions);
});
diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html
index d9cad0feff..37f2d0085f 100644
--- a/examples/html/entityProperties.html
+++ b/examples/html/entityProperties.html
@@ -360,6 +360,10 @@
var elVoxelVolumeSizeZ = document.getElementById("property-voxel-volume-size-z");
var elVoxelSurfaceStyle = document.getElementById("property-voxel-surface-style");
+ var elHyperlinkHref = document.getElementById("property-hyperlink-href");
+ var elHyperlinkDescription = document.getElementById("property-hyperlink-description");
+
+
if (window.EventBridge !== undefined) {
EventBridge.scriptEventReceived.connect(function(data) {
@@ -467,6 +471,9 @@
elScriptURL.value = properties.script;
elUserData.value = properties.userData;
+ elHyperlinkHref.value = properties.href;
+ elHyperlinkDescription.value = properties.description;
+
for (var i = 0; i < allSections.length; i++) {
for (var j = 0; j < allSections[i].length; j++) {
allSections[i][j].style.display = 'none';
@@ -612,6 +619,8 @@
elLocked.addEventListener('change', createEmitCheckedPropertyUpdateFunction('locked'));
elName.addEventListener('change', createEmitTextPropertyUpdateFunction('name'));
+ elHyperlinkHref.addEventListener('change', createEmitTextPropertyUpdateFunction('href'));
+ elHyperlinkDescription.addEventListener('change', createEmitTextPropertyUpdateFunction('description'));
elVisible.addEventListener('change', createEmitCheckedPropertyUpdateFunction('visible'));
var positionChangeFunction = createEmitVec3PropertyUpdateFunction(
@@ -850,6 +859,9 @@
elVoxelVolumeSizeZ.addEventListener('change', voxelVolumeSizeChangeFunction);
elVoxelSurfaceStyle.addEventListener('change', createEmitTextPropertyUpdateFunction('voxelSurfaceStyle'));
+ var hyperlinkChangeFunction = createEmitGroupTextPropertyUpdateFunction('hyperlink','href');
+ var hyperlinkChangeFunction = createEmitGroupTextPropertyUpdateFunction('hyperlink','description');
+
elMoveSelectionToGrid.addEventListener("click", function() {
EventBridge.emitWebEvent(JSON.stringify({
@@ -937,6 +949,18 @@
+
+
+
Hyperlink
+
Href
+
+
+
+
Description
+
+
+
+
Locked
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 188ae6eaf9..1763623fa6 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -524,6 +524,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
_window->setVisible(true);
_glWidget->setFocusPolicy(Qt::StrongFocus);
_glWidget->setFocus();
+ _glWidget->setCursor(Qt::BlankCursor);
// enable mouse tracking; otherwise, we only get drag events
_glWidget->setMouseTracking(true);
@@ -1891,8 +1892,6 @@ void Application::setEnableVRMode(bool enableVRMode) {
}
resizeGL();
-
- updateCursorVisibility();
}
void Application::setLowVelocityFilter(bool lowVelocityFilter) {
@@ -2401,19 +2400,8 @@ void Application::updateCursor(float deltaTime) {
lastMousePos = QCursor::pos();
}
-void Application::updateCursorVisibility() {
- if (!_cursorVisible ||
- Menu::getInstance()->isOptionChecked(MenuOption::EnableVRMode) ||
- Menu::getInstance()->isOptionChecked(MenuOption::Enable3DTVMode)) {
- _window->setCursor(Qt::BlankCursor);
- } else {
- _window->unsetCursor();
- }
-}
-
void Application::setCursorVisible(bool visible) {
_cursorVisible = visible;
- updateCursorVisibility();
}
void Application::update(float deltaTime) {
diff --git a/interface/src/Application.h b/interface/src/Application.h
index b74b3a0355..f63802ce24 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -475,8 +475,6 @@ private:
void updateProjectionMatrix();
void updateProjectionMatrix(Camera& camera, bool updateViewFrustum = true);
- void updateCursorVisibility();
-
void sendPingPackets();
void initDisplay();
diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp
index 8708a2b2b0..02af30b426 100644
--- a/interface/src/avatar/Avatar.cpp
+++ b/interface/src/avatar/Avatar.cpp
@@ -304,6 +304,7 @@ bool Avatar::addToScene(AvatarSharedPointer self, std::shared_ptr
void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_renderItemID);
_skeletonModel.removeFromScene(scene, pendingChanges);
+ getHead()->getFaceModel().removeFromScene(scene, pendingChanges);
}
void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition, bool postLighting) {
diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp
index 49a8012cd9..f16173b79e 100644
--- a/interface/src/avatar/AvatarManager.cpp
+++ b/interface/src/avatar/AvatarManager.cpp
@@ -55,7 +55,7 @@ AvatarManager::AvatarManager(QObject* parent) :
_avatarFades() {
// register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar
qRegisterMetaType >("NodeWeakPointer");
- _myAvatar = std::shared_ptr(new MyAvatar());
+ _myAvatar = std::make_shared();
}
void AvatarManager::init() {
@@ -97,9 +97,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
// simulate avatars
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {
- Avatar* avatar = reinterpret_cast(avatarIterator.value().get());
+ auto avatar = std::dynamic_pointer_cast(avatarIterator.value());
- if (avatar == _myAvatar.get() || !avatar->isInitialized()) {
+ if (avatar == _myAvatar || !avatar->isInitialized()) {
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
// DO NOT update or fade out uninitialized Avatars
++avatarIterator;
@@ -121,26 +121,30 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
const float SHRINK_RATE = 0.9f;
const float MIN_FADE_SCALE = 0.001f;
-
+
+ render::ScenePointer scene = Application::getInstance()->getMain3DScene();
+ render::PendingChanges pendingChanges;
while (fadingIterator != _avatarFades.end()) {
- Avatar* avatar = static_cast(fadingIterator->get());
+ auto avatar = std::static_pointer_cast(*fadingIterator);
avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true);
if (avatar->getTargetScale() < MIN_FADE_SCALE) {
+ avatar->removeFromScene(*fadingIterator, scene, pendingChanges);
fadingIterator = _avatarFades.erase(fadingIterator);
} else {
avatar->simulate(deltaTime);
++fadingIterator;
}
}
+ scene->enqueuePendingChanges(pendingChanges);
}
AvatarSharedPointer AvatarManager::newSharedAvatar() {
- return AvatarSharedPointer(new Avatar());
+ return AvatarSharedPointer(std::make_shared());
}
// virtual
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) {
- std::shared_ptr avatar = std::dynamic_pointer_cast(AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer));
+ auto avatar = std::dynamic_pointer_cast(AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer));
render::ScenePointer scene = Application::getInstance()->getMain3DScene();
render::PendingChanges pendingChanges;
avatar->addToScene(avatar, scene, pendingChanges);
@@ -171,10 +175,6 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) {
_avatarFades.push_back(avatarIterator.value());
_avatarHash.erase(avatarIterator);
}
- render::ScenePointer scene = Application::getInstance()->getMain3DScene();
- render::PendingChanges pendingChanges;
- avatar->removeFromScene(avatar, scene, pendingChanges);
- scene->enqueuePendingChanges(pendingChanges);
}
}
@@ -182,12 +182,12 @@ void AvatarManager::clearOtherAvatars() {
// clear any avatars that came from an avatar-mixer
AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) {
- Avatar* avatar = reinterpret_cast(avatarIterator.value().get());
- if (avatar == _myAvatar.get() || !avatar->isInitialized()) {
+ auto avatar = std::static_pointer_cast(avatarIterator.value());
+ if (avatar == _myAvatar || !avatar->isInitialized()) {
// don't remove myAvatar or uninitialized avatars from the list
++avatarIterator;
} else {
- removeAvatarMotionState(avatar);
+ removeAvatarMotionState(avatar.get());
_avatarFades.push_back(avatarIterator.value());
avatarIterator = _avatarHash.erase(avatarIterator);
}
@@ -250,7 +250,7 @@ void AvatarManager::handleCollisionEvents(CollisionEvents& collisionEvents) {
void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) {
AvatarHash::iterator avatarItr = _avatarHash.find(id);
if (avatarItr != _avatarHash.end()) {
- Avatar* avatar = static_cast(avatarItr.value().get());
+ auto avatar = std::static_pointer_cast(avatarItr.value());
AvatarMotionState* motionState = avatar->_motionState;
if (motionState) {
motionState->addDirtyFlags(EntityItem::DIRTY_SHAPE);
@@ -259,7 +259,7 @@ void AvatarManager::updateAvatarPhysicsShape(const QUuid& id) {
avatar->computeShapeInfo(shapeInfo);
btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo);
if (shape) {
- AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
+ AvatarMotionState* motionState = new AvatarMotionState(avatar.get(), shape);
avatar->_motionState = motionState;
_motionStatesToAdd.insert(motionState);
_avatarMotionStates.insert(motionState);
diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp
index e51522bb7f..bc8047fc98 100644
--- a/interface/src/ui/ApplicationOverlay.cpp
+++ b/interface/src/ui/ApplicationOverlay.cpp
@@ -267,9 +267,8 @@ void ApplicationOverlay::displayOverlayTexture() {
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
- if (_alpha < 1.0) {
- glEnable(GL_BLEND);
- }
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glViewport(0, 0, qApp->getDeviceSize().width(), qApp->getDeviceSize().height());
static const glm::vec2 topLeft(-1, 1);
@@ -277,9 +276,38 @@ void ApplicationOverlay::displayOverlayTexture() {
static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
- DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
+ DependencyManager::get()->renderQuad(
+ topLeft, bottomRight,
+ texCoordTopLeft, texCoordBottomRight,
glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
});
+
+ if (!_crosshairTexture) {
+ _crosshairTexture = DependencyManager::get()->
+ getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
+ }
+
+ //draw the mouse pointer
+ glm::vec2 canvasSize = qApp->getCanvasSize();
+ glm::vec2 mouseSize = 32.0f / canvasSize;
+ auto mouseTopLeft = topLeft * mouseSize;
+ auto mouseBottomRight = bottomRight * mouseSize;
+ vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY());
+ mousePosition /= canvasSize;
+ mousePosition *= 2.0f;
+ mousePosition -= 1.0f;
+ mousePosition.y *= -1.0f;
+
+ glEnable(GL_TEXTURE_2D);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
+ glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f };
+ DependencyManager::get()->renderQuad(
+ mouseTopLeft + mousePosition, mouseBottomRight + mousePosition,
+ texCoordTopLeft, texCoordBottomRight,
+ reticleColor);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
+ glDisable(GL_TEXTURE_2D);
} glPopMatrix();
}
@@ -428,6 +456,9 @@ void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float
}
//draw the mouse pointer
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
glm::vec2 canvasSize = qApp->getCanvasSize();
const float reticleSize = 40.0f / canvasSize.x * quadWidth;
@@ -557,7 +588,9 @@ void ApplicationOverlay::renderPointers() {
_crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png");
}
glEnable(GL_TEXTURE_2D);
-
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
@@ -719,8 +752,14 @@ void ApplicationOverlay::renderControllerPointers() {
}
void ApplicationOverlay::renderPointersOculus() {
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_TEXTURE_2D);
+
glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture));
glDisable(GL_DEPTH_TEST);
+
glMatrixMode(GL_MODELVIEW);
//Controller Pointers
@@ -745,6 +784,8 @@ void ApplicationOverlay::renderPointersOculus() {
}
glEnable(GL_DEPTH_TEST);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
}
//Renders a small magnification of the currently bound texture at the coordinates
diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp
index 4a10aad95d..f64dad0ef4 100644
--- a/libraries/entities/src/EntityItem.cpp
+++ b/libraries/entities/src/EntityItem.cpp
@@ -70,7 +70,9 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
_dirtyFlags(0),
_element(nullptr),
_physicsInfo(nullptr),
- _simulated(false)
+ _simulated(false),
+ _href(""),
+ _description("")
{
quint64 now = usecTimestampNow();
_lastSimulated = now;
@@ -117,6 +119,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param
requestedProperties += PROP_MARKETPLACE_ID;
requestedProperties += PROP_NAME;
requestedProperties += PROP_SIMULATOR_ID;
+ requestedProperties += PROP_HREF;
+ requestedProperties += PROP_DESCRIPTION;
return requestedProperties;
}
@@ -246,6 +250,9 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL());
+ APPEND_ENTITY_PROPERTY(PROP_HREF, getHref());
+ APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription());
+
appendSubclassData(packetData, params, entityTreeElementExtraEncodeData,
requestedProperties,
@@ -573,6 +580,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
+ READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref);
+ READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription);
+
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData);
////////////////////////////////////
@@ -905,6 +915,8 @@ EntityItemProperties EntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulatorID, getSimulatorID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(marketplaceID, getMarketplaceID);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref);
+ COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription);
properties._defaultSettings = false;
@@ -963,6 +975,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(marketplaceID, setMarketplaceID);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref);
+ SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription);
if (somethingChanged) {
uint64_t now = usecTimestampNow();
diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h
index 77a6627853..a145c4c236 100644
--- a/libraries/entities/src/EntityItem.h
+++ b/libraries/entities/src/EntityItem.h
@@ -203,7 +203,14 @@ public:
inline const glm::quat& getRotation() const { return _transform.getRotation(); }
inline void setRotation(const glm::quat& rotation) { _transform.setRotation(rotation); }
-
+
+ // Hyperlink related getters and setters
+ QString getHref() const { return _href; }
+ void setHref(QString value) { _href = value; }
+
+ QString getDescription() const { return _description; }
+ void setDescription(QString value) { _description = value; }
+
/// Dimensions in meters (0.0 - TREE_SCALE)
inline const glm::vec3& getDimensions() const { return _transform.getScale(); }
virtual void setDimensions(const glm::vec3& value);
@@ -415,6 +422,8 @@ protected:
quint64 _simulatorIDChangedTime; // when was _simulatorID last updated?
QString _marketplaceID;
QString _name;
+ QString _href; //Hyperlink href
+ QString _description; //Hyperlink description
// NOTE: Damping is applied like this: v *= pow(1 - damping, dt)
//
diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp
index 90f2b22698..cbb3b1dc31 100644
--- a/libraries/entities/src/EntityItemProperties.cpp
+++ b/libraries/entities/src/EntityItemProperties.cpp
@@ -347,6 +347,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle);
CHECK_PROPERTY_CHANGE(PROP_LINE_WIDTH, lineWidth);
CHECK_PROPERTY_CHANGE(PROP_LINE_POINTS, linePoints);
+ CHECK_PROPERTY_CHANGE(PROP_HREF, href);
+ CHECK_PROPERTY_CHANGE(PROP_DESCRIPTION, description);
+
changedProperties += _stage.getChangedProperties();
changedProperties += _atmosphere.getChangedProperties();
changedProperties += _skybox.getChangedProperties();
@@ -439,7 +442,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(voxelSurfaceStyle);
COPY_PROPERTY_TO_QSCRIPTVALUE(lineWidth);
COPY_PROPERTY_TO_QSCRIPTVALUE(linePoints);
-
+ COPY_PROPERTY_TO_QSCRIPTVALUE(href);
+ COPY_PROPERTY_TO_QSCRIPTVALUE(description);
+
// Sitting properties support
if (!skipDefaults) {
QScriptValue sittingPoints = engine->newObject();
@@ -548,6 +553,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle);
COPY_PROPERTY_FROM_QSCRIPTVALUE(lineWidth, float, setLineWidth);
COPY_PROPERTY_FROM_QSCRIPTVALUE(linePoints, qVectorVec3, setLinePoints);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(href, QString, setHref);
+ COPY_PROPERTY_FROM_QSCRIPTVALUE(description, QString, setDescription);
+
if (!honorReadOnly) {
// this is used by the json reader to set things that we don't want javascript to able to affect.
@@ -712,6 +720,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked());
APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData());
APPEND_ENTITY_PROPERTY(PROP_SIMULATOR_ID, properties.getSimulatorID());
+ APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref());
+ APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription());
if (properties.getType() == EntityTypes::Web) {
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl());
@@ -962,6 +972,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATOR_ID, QUuid, setSimulatorID);
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HREF, QString, setHref);
+ READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription);
if (properties.getType() == EntityTypes::Web) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl);
@@ -1147,6 +1159,9 @@ void EntityItemProperties::markAllChanged() {
_lineWidthChanged = true;
_linePointsChanged = true;
+ _hrefChanged = true;
+ _descriptionChanged = true;
+
}
/// The maximum bounding cube for the entity, independent of it's rotation.
diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h
index 3c8133af8f..068bc98f7e 100644
--- a/libraries/entities/src/EntityItemProperties.h
+++ b/libraries/entities/src/EntityItemProperties.h
@@ -148,6 +148,8 @@ public:
DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString);
DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float);
DEFINE_PROPERTY_REF(LINE_POINTS, LinePoints, linePoints, QVector);
+ DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString);
+ DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString);
static QString getBackgroundModeString(BackgroundMode mode);
@@ -295,6 +297,8 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelData, voxelData, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelSurfaceStyle, voxelSurfaceStyle, "");
+ DEBUG_PROPERTY_IF_CHANGED(debug, properties, Href, href, "");
+ DEBUG_PROPERTY_IF_CHANGED(debug, properties, Description, description, "");
properties.getStage().debugDump();
properties.getAtmosphere().debugDump();
diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h
index 8eb09fece0..f1ebdb8a1f 100644
--- a/libraries/entities/src/EntityPropertyFlags.h
+++ b/libraries/entities/src/EntityPropertyFlags.h
@@ -117,6 +117,10 @@ enum EntityPropertyList {
//for lines
PROP_LINE_WIDTH,
PROP_LINE_POINTS,
+
+ // used by hyperlinks
+ PROP_HREF,
+ PROP_DESCRIPTION,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties ABOVE this line
diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp
index e7e1c90b41..094536f63a 100644
--- a/libraries/entities/src/LineEntityItem.cpp
+++ b/libraries/entities/src/LineEntityItem.cpp
@@ -18,6 +18,7 @@
#include "EntityTree.h"
#include "EntitiesLogging.h"
#include "EntityTreeElement.h"
+#include "OctreeConstants.h"
@@ -90,8 +91,8 @@ void LineEntityItem::setLinePoints(const QVector& points) {
for (int i = 0; i < points.size(); i++) {
glm::vec3 point = points.at(i);
// Make sure all of our points are valid numbers.
- // Must be greater than 0 because vector component is set to 0 if it is invalid data
- if (point.x > 0 && point.y > 0 && point.z > 0){
+ // Must be greater than 0 because vector component is set to 0 if it is invalid data. Also should never be greater than TREE_SCALE
+ if ( (point.x > 0 && point.x < TREE_SCALE) && (point.y > 0 && point.y < TREE_SCALE) && (point.z > 0 && point.z < TREE_SCALE) ) {
sanitizedPoints << point;
} else {
++invalidPoints;
diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp
index 464deb1059..f282f7e35d 100644
--- a/libraries/fbx/src/FBXReader.cpp
+++ b/libraries/fbx/src/FBXReader.cpp
@@ -1902,8 +1902,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping,
} else {
material._material->setDiffuse(material.diffuse);
}
- material._material->setSpecular(material.specular);
- material._material->setShininess(material.shininess);
+ material._material->setMetallic(glm::length(material.specular));
+ material._material->setGloss(material.shininess);
if (material.opacity <= 0.0f) {
material._material->setOpacity(1.0f);
diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp
index 4a8a2fc53d..080fb98690 100644
--- a/libraries/fbx/src/OBJReader.cpp
+++ b/libraries/fbx/src/OBJReader.cpp
@@ -134,8 +134,8 @@ void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID) {
meshPart._material = model::MaterialPointer(new model::Material());
meshPart._material->setDiffuse(glm::vec3(1.0, 1.0, 1.0));
meshPart._material->setOpacity(1.0);
- meshPart._material->setSpecular(glm::vec3(1.0, 1.0, 1.0));
- meshPart._material->setShininess(96.0);
+ meshPart._material->setMetallic(0.0);
+ meshPart._material->setGloss(96.0);
meshPart._material->setEmissive(glm::vec3(0.0, 0.0, 0.0));
}
@@ -481,8 +481,8 @@ FBXGeometry OBJReader::readOBJ(QIODevice* device, const QVariantHash& mapping, Q
meshPart.specularTexture.filename = material->specularTextureFilename;
// ... and some things are set in the underlying material.
meshPart._material->setDiffuse(material->diffuseColor);
- meshPart._material->setSpecular(material->specularColor);
- meshPart._material->setShininess(material->shininess);
+ meshPart._material->setMetallic(glm::length(material->specularColor));
+ meshPart._material->setGloss(material->shininess);
meshPart._material->setOpacity(material->opacity);
}
// qCDebug(modelformat) << "OBJ Reader part:" << meshPartCount << "name:" << leadFace.groupName << "material:" << groupMaterialName << "diffuse:" << meshPart._material->getDiffuse() << "faces:" << faceGroup.count() << "triangle indices will start with:" << mesh.vertices.count();
@@ -567,10 +567,10 @@ void fbxDebugDump(const FBXGeometry& fbxgeo) {
qCDebug(modelformat) << " quadIndices.count() =" << meshPart.quadIndices.count();
qCDebug(modelformat) << " triangleIndices.count() =" << meshPart.triangleIndices.count();
qCDebug(modelformat) << " diffuseColor =" << meshPart.diffuseColor << "mat =" << meshPart._material->getDiffuse();
- qCDebug(modelformat) << " specularColor =" << meshPart.specularColor << "mat =" << meshPart._material->getSpecular();
+ qCDebug(modelformat) << " specularColor =" << meshPart.specularColor << "mat =" << meshPart._material->getMetallic();
qCDebug(modelformat) << " emissiveColor =" << meshPart.emissiveColor << "mat =" << meshPart._material->getEmissive();
qCDebug(modelformat) << " emissiveParams =" << meshPart.emissiveParams;
- qCDebug(modelformat) << " shininess =" << meshPart.shininess << "mat =" << meshPart._material->getShininess();
+ qCDebug(modelformat) << " gloss =" << meshPart.shininess << "mat =" << meshPart._material->getGloss();
qCDebug(modelformat) << " opacity =" << meshPart.opacity << "mat =" << meshPart._material->getOpacity();
qCDebug(modelformat) << " materialID =" << meshPart.materialID;
qCDebug(modelformat) << " diffuse texture =" << meshPart.diffuseTexture.filename;
diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h
index 9036f0f6db..d5c3635816 100755
--- a/libraries/gpu/src/gpu/Texture.h
+++ b/libraries/gpu/src/gpu/Texture.h
@@ -437,6 +437,8 @@ public:
explicit operator bool() const { return bool(_texture); }
bool operator !() const { return (!_texture); }
+
+ bool isValid() const { return bool(_texture); }
};
typedef std::vector TextureViews;
diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp
index 55572a5122..a3448889b0 100755
--- a/libraries/model/src/model/Material.cpp
+++ b/libraries/model/src/model/Material.cpp
@@ -14,7 +14,7 @@ using namespace model;
using namespace gpu;
Material::Material() :
- _flags(0),
+ _key(0),
_schemaBuffer(),
_textureMap() {
@@ -26,13 +26,13 @@ Material::Material() :
}
Material::Material(const Material& material) :
- _flags(material._flags),
+ _key(material._key),
_schemaBuffer(material._schemaBuffer),
_textureMap(material._textureMap) {
}
Material& Material::operator= (const Material& material) {
- _flags = (material._flags);
+ _key = (material._key);
_schemaBuffer = (material._schemaBuffer);
_textureMap = (material._textureMap);
@@ -43,52 +43,32 @@ Material::~Material() {
}
void Material::setDiffuse(const Color& diffuse) {
- if (glm::any(glm::greaterThan(diffuse, Color(0.0f)))) {
- _flags.set(DIFFUSE_BIT);
- } else {
- _flags.reset(DIFFUSE_BIT);
- }
+ _key.setDiffuse(glm::any(glm::greaterThan(diffuse, Color(0.0f))));
_schemaBuffer.edit()._diffuse = diffuse;
}
-void Material::setSpecular(const Color& specular) {
- if (glm::any(glm::greaterThan(specular, Color(0.0f)))) {
- _flags.set(SPECULAR_BIT);
- } else {
- _flags.reset(SPECULAR_BIT);
- }
- _schemaBuffer.edit()._specular = specular;
+void Material::setMetallic(float metallic) {
+ _key.setMetallic(metallic > 0.0f);
+ _schemaBuffer.edit()._metallic = glm::vec3(metallic);
}
void Material::setEmissive(const Color& emissive) {
- if (glm::any(glm::greaterThan(emissive, Color(0.0f)))) {
- _flags.set(EMISSIVE_BIT);
- } else {
- _flags.reset(EMISSIVE_BIT);
- }
+ _key.setEmissive(glm::any(glm::greaterThan(emissive, Color(0.0f))));
_schemaBuffer.edit()._emissive = emissive;
}
-void Material::setShininess(float shininess) {
- if (shininess > 0.0f) {
- _flags.set(SHININESS_BIT);
- } else {
- _flags.reset(SHININESS_BIT);
- }
- _schemaBuffer.edit()._shininess = shininess;
+void Material::setGloss(float gloss) {
+ _key.setGloss((gloss > 0.0f));
+ _schemaBuffer.edit()._gloss = gloss;
}
void Material::setOpacity(float opacity) {
- if (opacity >= 1.0f) {
- _flags.reset(TRANSPARENT_BIT);
- } else {
- _flags.set(TRANSPARENT_BIT);
- }
+ _key.setTransparent((opacity < 1.0f));
_schemaBuffer.edit()._opacity = opacity;
}
void Material::setTextureView(MapChannel channel, const gpu::TextureView& view) {
- _flags.set(DIFFUSE_MAP_BIT + channel);
+ _key.setMapChannel(channel, (view.isValid()));
_textureMap[channel] = view;
}
diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h
index ea0ab808e9..392fd918a1 100755
--- a/libraries/model/src/model/Material.h
+++ b/libraries/model/src/model/Material.h
@@ -23,6 +23,177 @@
namespace model {
+// Material Key is a coarse trait description of a material used to classify the materials
+class MaterialKey {
+public:
+ enum FlagBit {
+ EMISSIVE_VAL_BIT = 0,
+ DIFFUSE_VAL_BIT,
+ METALLIC_VAL_BIT,
+ GLOSS_VAL_BIT,
+ TRANSPARENT_VAL_BIT,
+
+ EMISSIVE_MAP_BIT,
+ DIFFUSE_MAP_BIT,
+ METALLIC_MAP_BIT,
+ GLOSS_MAP_BIT,
+ TRANSPARENT_MAP_BIT,
+ NORMAL_MAP_BIT,
+
+ NUM_FLAGS,
+ };
+ typedef std::bitset Flags;
+
+ enum MapChannel {
+ EMISSIVE_MAP = 0,
+ DIFFUSE_MAP,
+ METALLIC_MAP,
+ GLOSS_MAP,
+ TRANSPARENT_MAP,
+ NORMAL_MAP,
+
+ NUM_MAP_CHANNELS,
+ };
+
+ // The signature is the Flags
+ Flags _flags;
+
+ MaterialKey() : _flags(0) {}
+ MaterialKey(const Flags& flags) : _flags(flags) {}
+
+ class Builder {
+ Flags _flags{ 0 };
+ public:
+ Builder() {}
+
+ MaterialKey build() const { return MaterialKey(_flags); }
+
+ Builder& withEmissive() { _flags.set(EMISSIVE_VAL_BIT); return (*this); }
+ Builder& withDiffuse() { _flags.set(DIFFUSE_VAL_BIT); return (*this); }
+ Builder& withMetallic() { _flags.set(METALLIC_VAL_BIT); return (*this); }
+ Builder& withGloss() { _flags.set(GLOSS_VAL_BIT); return (*this); }
+ Builder& withTransparent() { _flags.set(TRANSPARENT_VAL_BIT); return (*this); }
+
+ Builder& withEmissiveMap() { _flags.set(EMISSIVE_MAP_BIT); return (*this); }
+ Builder& withDiffuseMap() { _flags.set(DIFFUSE_MAP_BIT); return (*this); }
+ Builder& withMetallicMap() { _flags.set(METALLIC_MAP_BIT); return (*this); }
+ Builder& withGlossMap() { _flags.set(GLOSS_MAP_BIT); return (*this); }
+ Builder& withTransparentMap() { _flags.set(TRANSPARENT_MAP_BIT); return (*this); }
+
+ Builder& withNormalMap() { _flags.set(NORMAL_MAP_BIT); return (*this); }
+
+ // Convenient standard keys that we will keep on using all over the place
+ static MaterialKey opaqueDiffuse() { return Builder().withDiffuse().build(); }
+ };
+
+ void setEmissive(bool value) { _flags.set(EMISSIVE_VAL_BIT, value); }
+ bool isEmissive() const { return _flags[EMISSIVE_VAL_BIT]; }
+
+ void setEmissiveMap(bool value) { _flags.set(EMISSIVE_MAP_BIT, value); }
+ bool isEmissiveMap() const { return _flags[EMISSIVE_MAP_BIT]; }
+
+ void setDiffuse(bool value) { _flags.set(DIFFUSE_VAL_BIT, value); }
+ bool isDiffuse() const { return _flags[DIFFUSE_VAL_BIT]; }
+
+ void setDiffuseMap(bool value) { _flags.set(DIFFUSE_MAP_BIT, value); }
+ bool isDiffuseMap() const { return _flags[DIFFUSE_MAP_BIT]; }
+
+ void setMetallic(bool value) { _flags.set(METALLIC_VAL_BIT, value); }
+ bool isMetallic() const { return _flags[METALLIC_VAL_BIT]; }
+
+ void setMetallicMap(bool value) { _flags.set(METALLIC_MAP_BIT, value); }
+ bool isMetallicMap() const { return _flags[METALLIC_MAP_BIT]; }
+
+ void setGloss(bool value) { _flags.set(GLOSS_VAL_BIT, value); }
+ bool isGloss() const { return _flags[GLOSS_VAL_BIT]; }
+
+ void setGlossMap(bool value) { _flags.set(GLOSS_MAP_BIT, value); }
+ bool isGlossMap() const { return _flags[GLOSS_MAP_BIT]; }
+
+ void setTransparent(bool value) { _flags.set(TRANSPARENT_VAL_BIT, value); }
+ bool isTransparent() const { return _flags[TRANSPARENT_VAL_BIT]; }
+ bool isOpaque() const { return !_flags[TRANSPARENT_VAL_BIT]; }
+
+ void setTransparentMap(bool value) { _flags.set(TRANSPARENT_MAP_BIT, value); }
+ bool isTransparentMap() const { return _flags[TRANSPARENT_MAP_BIT]; }
+
+ void setNormalMap(bool value) { _flags.set(NORMAL_MAP_BIT, value); }
+ bool isNormalMap() const { return _flags[NORMAL_MAP_BIT]; }
+
+ void setMapChannel(MapChannel channel, bool value) { _flags.set(EMISSIVE_MAP_BIT + channel, value); }
+ bool isMapChannel(MapChannel channel) const { return _flags[EMISSIVE_MAP_BIT + channel]; }
+
+};
+
+
+class MaterialFilter {
+public:
+ MaterialKey::Flags _value{ 0 };
+ MaterialKey::Flags _mask{ 0 };
+
+
+ MaterialFilter(const MaterialKey::Flags& value = MaterialKey::Flags(0), const MaterialKey::Flags& mask = MaterialKey::Flags(0)) : _value(value), _mask(mask) {}
+
+ class Builder {
+ MaterialKey::Flags _value{ 0 };
+ MaterialKey::Flags _mask{ 0 };
+ public:
+ Builder() {}
+
+ MaterialFilter build() const { return MaterialFilter(_value, _mask); }
+
+ Builder& withoutEmissive() { _value.reset(MaterialKey::EMISSIVE_VAL_BIT); _mask.set(MaterialKey::EMISSIVE_VAL_BIT); return (*this); }
+ Builder& withEmissive() { _value.set(MaterialKey::EMISSIVE_VAL_BIT); _mask.set(MaterialKey::EMISSIVE_VAL_BIT); return (*this); }
+
+ Builder& withoutEmissiveMap() { _value.reset(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT); return (*this); }
+ Builder& withEmissiveMap() { _value.set(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT); return (*this); }
+
+ Builder& withoutDiffuse() { _value.reset(MaterialKey::DIFFUSE_VAL_BIT); _mask.set(MaterialKey::DIFFUSE_VAL_BIT); return (*this); }
+ Builder& withDiffuse() { _value.set(MaterialKey::DIFFUSE_VAL_BIT); _mask.set(MaterialKey::DIFFUSE_VAL_BIT); return (*this); }
+
+ Builder& withoutDiffuseMap() { _value.reset(MaterialKey::DIFFUSE_MAP_BIT); _mask.set(MaterialKey::DIFFUSE_MAP_BIT); return (*this); }
+ Builder& withDiffuseMap() { _value.set(MaterialKey::DIFFUSE_MAP_BIT); _mask.set(MaterialKey::DIFFUSE_MAP_BIT); return (*this); }
+
+ Builder& withoutMetallic() { _value.reset(MaterialKey::METALLIC_VAL_BIT); _mask.set(MaterialKey::METALLIC_VAL_BIT); return (*this); }
+ Builder& withMetallic() { _value.set(MaterialKey::METALLIC_VAL_BIT); _mask.set(MaterialKey::METALLIC_VAL_BIT); return (*this); }
+
+ Builder& withoutMetallicMap() { _value.reset(MaterialKey::METALLIC_MAP_BIT); _mask.set(MaterialKey::METALLIC_MAP_BIT); return (*this); }
+ Builder& withMetallicMap() { _value.set(MaterialKey::METALLIC_MAP_BIT); _mask.set(MaterialKey::METALLIC_MAP_BIT); return (*this); }
+
+ Builder& withoutGloss() { _value.reset(MaterialKey::GLOSS_VAL_BIT); _mask.set(MaterialKey::GLOSS_VAL_BIT); return (*this); }
+ Builder& withGloss() { _value.set(MaterialKey::GLOSS_VAL_BIT); _mask.set(MaterialKey::GLOSS_VAL_BIT); return (*this); }
+
+ Builder& withoutGlossMap() { _value.reset(MaterialKey::GLOSS_MAP_BIT); _mask.set(MaterialKey::GLOSS_MAP_BIT); return (*this); }
+ Builder& withGlossMap() { _value.set(MaterialKey::GLOSS_MAP_BIT); _mask.set(MaterialKey::GLOSS_MAP_BIT); return (*this); }
+
+ Builder& withoutTransparent() { _value.reset(MaterialKey::TRANSPARENT_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_VAL_BIT); return (*this); }
+ Builder& withTransparent() { _value.set(MaterialKey::TRANSPARENT_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_VAL_BIT); return (*this); }
+
+ Builder& withoutTransparentMap() { _value.reset(MaterialKey::TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::TRANSPARENT_MAP_BIT); return (*this); }
+ Builder& withTransparentMap() { _value.set(MaterialKey::TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::TRANSPARENT_MAP_BIT); return (*this); }
+
+ Builder& withoutNormalMap() { _value.reset(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT); return (*this); }
+ Builder& withNormalMap() { _value.set(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT); return (*this); }
+
+ // Convenient standard keys that we will keep on using all over the place
+ static MaterialFilter opaqueDiffuse() { return Builder().withDiffuse().withoutTransparent().build(); }
+ };
+
+ // Item Filter operator testing if a key pass the filter
+ bool test(const MaterialKey& key) const { return (key._flags & _mask) == (_value & _mask); }
+
+ class Less {
+ public:
+ bool operator() (const MaterialFilter& left, const MaterialFilter& right) const {
+ if (left._value.to_ulong() == right._value.to_ulong()) {
+ return left._mask.to_ulong() < right._mask.to_ulong();
+ } else {
+ return left._value.to_ulong() < right._value.to_ulong();
+ }
+ }
+ };
+};
+
class Material {
public:
typedef gpu::BufferView UniformBufferView;
@@ -30,52 +201,27 @@ public:
typedef glm::vec3 Color;
- enum MapChannel {
- DIFFUSE_MAP = 0,
- SPECULAR_MAP,
- SHININESS_MAP,
- EMISSIVE_MAP,
- OPACITY_MAP,
- NORMAL_MAP,
-
- NUM_MAPS,
- };
+ typedef MaterialKey::MapChannel MapChannel;
typedef std::map TextureMap;
- typedef std::bitset MapFlags;
-
- enum FlagBit {
- DIFFUSE_BIT = 0,
- SPECULAR_BIT,
- SHININESS_BIT,
- EMISSIVE_BIT,
- TRANSPARENT_BIT,
-
- DIFFUSE_MAP_BIT,
- SPECULAR_MAP_BIT,
- SHININESS_MAP_BIT,
- EMISSIVE_MAP_BIT,
- OPACITY_MAP_BIT,
- NORMAL_MAP_BIT,
-
- NUM_FLAGS,
- };
- typedef std::bitset Flags;
+ typedef std::bitset MapFlags;
Material();
Material(const Material& material);
Material& operator= (const Material& material);
virtual ~Material();
+ const MaterialKey& getKey() const { return _key; }
+
const Color& getEmissive() const { return _schemaBuffer.get()._emissive; }
const Color& getDiffuse() const { return _schemaBuffer.get()._diffuse; }
- const Color& getSpecular() const { return _schemaBuffer.get()._specular; }
- float getShininess() const { return _schemaBuffer.get()._shininess; }
+ float getMetallic() const { return _schemaBuffer.get()._metallic.x; }
+ float getGloss() const { return _schemaBuffer.get()._gloss; }
float getOpacity() const { return _schemaBuffer.get()._opacity; }
- void setDiffuse(const Color& diffuse);
- void setSpecular(const Color& specular);
void setEmissive(const Color& emissive);
- void setShininess(float shininess);
+ void setDiffuse(const Color& diffuse);
+ void setMetallic(float metallic);
+ void setGloss(float gloss);
void setOpacity(float opacity);
// Schema to access the attribute values of the material
@@ -84,8 +230,8 @@ public:
Color _diffuse{0.5f};
float _opacity{1.f};
- Color _specular{0.03f};
- float _shininess{0.1f};
+ Color _metallic{0.03f};
+ float _gloss{0.1f};
Color _emissive{0.0f};
float _spare0{0.0f};
glm::vec4 _spareVec4{0.0f}; // for alignment beauty, Material size == Mat4x4
@@ -100,7 +246,7 @@ public:
protected:
- Flags _flags;
+ MaterialKey _key;
UniformBufferView _schemaBuffer;
TextureMap _textureMap;
diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp
index a34a3be3fd..933c737b83 100755
--- a/libraries/model/src/model/Skybox.cpp
+++ b/libraries/model/src/model/Skybox.cpp
@@ -44,70 +44,73 @@ void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) {
- if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
+ if (skybox.getCubemap()) {
+ if (skybox.getCubemap()->isDefined()) {
- static gpu::PipelinePointer thePipeline;
- static gpu::BufferPointer theBuffer;
- static gpu::Stream::FormatPointer theFormat;
- static gpu::BufferPointer theConstants;
- int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader
- if (!thePipeline) {
- auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert)));
- auto skyFS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(Skybox_frag)));
- auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyVS, skyFS));
+ static gpu::PipelinePointer thePipeline;
+ static gpu::BufferPointer theBuffer;
+ static gpu::Stream::FormatPointer theFormat;
+ static gpu::BufferPointer theConstants;
+ int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader
+ if (!thePipeline) {
+ auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert)));
+ auto skyFS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(Skybox_frag)));
+ auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyVS, skyFS));
- gpu::Shader::BindingSet bindings;
- bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), 0));
- if (!gpu::Shader::makeProgram(*skyShader, bindings)) {
+ gpu::Shader::BindingSet bindings;
+ bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), 0));
+ if (!gpu::Shader::makeProgram(*skyShader, bindings)) {
- }
+ }
- SKYBOX_CONSTANTS_SLOT = skyShader->getBuffers().findLocation("skyboxBuffer");
- if (SKYBOX_CONSTANTS_SLOT == gpu::Shader::INVALID_LOCATION) {
- SKYBOX_CONSTANTS_SLOT = skyShader->getUniforms().findLocation("skyboxBuffer");
- }
+ SKYBOX_CONSTANTS_SLOT = skyShader->getBuffers().findLocation("skyboxBuffer");
+ if (SKYBOX_CONSTANTS_SLOT == gpu::Shader::INVALID_LOCATION) {
+ SKYBOX_CONSTANTS_SLOT = skyShader->getUniforms().findLocation("skyboxBuffer");
+ }
- auto skyState = gpu::StatePointer(new gpu::State());
+ auto skyState = gpu::StatePointer(new gpu::State());
- thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));
+ thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));
- const float CLIP = 1.0;
- const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}};
- theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices));
+ const float CLIP = 1.0;
+ const glm::vec2 vertices[4] = { {-CLIP, -CLIP}, {CLIP, -CLIP}, {-CLIP, CLIP}, {CLIP, CLIP}};
+ theBuffer.reset(new gpu::Buffer(sizeof(vertices), (const gpu::Byte*) vertices));
- theFormat.reset(new gpu::Stream::Format());
- theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
+ theFormat.reset(new gpu::Stream::Format());
+ theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
- auto color = glm::vec4(1.0f);
- theConstants.reset(new gpu::Buffer(sizeof(color), (const gpu::Byte*) &color));
+ auto color = glm::vec4(1.0f);
+ theConstants.reset(new gpu::Buffer(sizeof(color), (const gpu::Byte*) &color));
+ }
+
+ glm::mat4 projMat;
+ viewFrustum.evalProjectionMatrix(projMat);
+
+ Transform viewTransform;
+ viewFrustum.evalViewTransform(viewTransform);
+
+ if (glm::all(glm::equal(skybox.getColor(), glm::vec3(0.0f)))) {
+ auto color = glm::vec4(1.0f);
+ theConstants->setSubData(0, sizeof(color), (const gpu::Byte*) &color);
+ } else {
+ theConstants->setSubData(0, sizeof(Color), (const gpu::Byte*) &skybox.getColor());
+ }
+
+ batch.setProjectionTransform(projMat);
+ batch.setViewTransform(viewTransform);
+ batch.setModelTransform(Transform()); // only for Mac
+ batch.setPipeline(thePipeline);
+ batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
+ batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize());
+ batch.setInputFormat(theFormat);
+ batch.setUniformTexture(0, skybox.getCubemap());
+ batch.draw(gpu::TRIANGLE_STRIP, 4);
}
- glm::mat4 projMat;
- viewFrustum.evalProjectionMatrix(projMat);
-
- Transform viewTransform;
- viewFrustum.evalViewTransform(viewTransform);
-
- if (glm::all(glm::equal(skybox.getColor(), glm::vec3(0.0f)))) {
- auto color = glm::vec4(1.0f);
- theConstants->setSubData(0, sizeof(color), (const gpu::Byte*) &color);
- } else {
- theConstants->setSubData(0, sizeof(Color), (const gpu::Byte*) &skybox.getColor());
- }
-
- batch.setProjectionTransform(projMat);
- batch.setViewTransform(viewTransform);
- batch.setModelTransform(Transform()); // only for Mac
- batch.setPipeline(thePipeline);
- batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
- batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize());
- batch.setInputFormat(theFormat);
- batch.setUniformTexture(0, skybox.getCubemap());
- batch.draw(gpu::TRIANGLE_STRIP, 4);
} else {
// skybox has no cubemap, just clear the color buffer
auto color = skybox.getColor();
- batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 1.0f), 0.f, 0);
+ batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.f, 0);
}
}
diff --git a/libraries/model/src/model/TextureStorage.h b/libraries/model/src/model/TextureStorage.h
index ebc027298b..a6752d21b2 100755
--- a/libraries/model/src/model/TextureStorage.h
+++ b/libraries/model/src/model/TextureStorage.h
@@ -24,7 +24,7 @@ typedef glm::vec3 Color;
class TextureUsage {
public:
gpu::Texture::Type _type{ gpu::Texture::TEX_2D };
- Material::MapFlags _materialUsage{ Material::DIFFUSE_MAP };
+ Material::MapFlags _materialUsage{ MaterialKey::DIFFUSE_MAP };
int _environmentUsage = 0;
};
diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp
index a86ce78655..642ca4748d 100644
--- a/libraries/networking/src/AddressManager.cpp
+++ b/libraries/networking/src/AddressManager.cpp
@@ -35,6 +35,7 @@ AddressManager::AddressManager() :
_positionGetter(NULL),
_orientationGetter(NULL)
{
+
}
bool AddressManager::isConnected() {
@@ -217,7 +218,7 @@ void AddressManager::goToAddressFromObject(const QVariantMap& dataObject, const
const QString DOMAIN_NETWORK_PORT_KEY = "network_port";
const QString DOMAIN_ICE_SERVER_ADDRESS_KEY = "ice_server_address";
- DependencyManager::get()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::HandleAddress);
+ DependencyManager::get()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::HandleAddress);
const QString DOMAIN_ID_KEY = "id";
QString domainIDString = domainObject[DOMAIN_ID_KEY].toString();
@@ -415,6 +416,9 @@ bool AddressManager::handleViewpoint(const QString& viewpointString, bool should
positionRegex.cap(2).toFloat(),
positionRegex.cap(3).toFloat());
+ // we're about to jump positions - store the current address in our history
+ addCurrentAddressToHistory();
+
if (!isNaN(newPosition.x) && !isNaN(newPosition.y) && !isNaN(newPosition.z)) {
glm::quat newOrientation;
@@ -467,6 +471,10 @@ bool AddressManager::handleUsername(const QString& lookupString) {
void AddressManager::setHost(const QString& host) {
if (host != _host) {
+
+ // if the host is being changed we should store current address in the history
+ addCurrentAddressToHistory();
+
_host = host;
emit hostChanged(_host);
}
@@ -474,7 +482,8 @@ void AddressManager::setHost(const QString& host) {
void AddressManager::setDomainInfo(const QString& hostname, quint16 port) {
- _host = hostname;
+ setHost(hostname);
+
_rootPlaceID = QUuid();
qCDebug(networking) << "Possible domain change required to connect to domain at" << hostname << "on" << port;
@@ -500,3 +509,22 @@ void AddressManager::copyAddress() {
void AddressManager::copyPath() {
QApplication::clipboard()->setText(currentPath());
}
+
+void AddressManager::addCurrentAddressToHistory() {
+ if (_lastHistoryAppend == 0) {
+ // we don't store the first address on application load
+ // just update the last append time so the next is stored
+ _lastHistoryAppend = usecTimestampNow();
+ } else {
+ const quint64 DOUBLE_STORE_THRESHOLD_USECS = 500000;
+
+ // avoid double storing when the host changes and the viewpoint changes immediately after
+ if (usecTimestampNow() - _lastHistoryAppend > DOUBLE_STORE_THRESHOLD_USECS) {
+ // add the current address to the history
+ _history.append(currentAddress());
+
+ // change our last history append to now
+ _lastHistoryAppend = usecTimestampNow();
+ }
+ }
+}
diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h
index 2b587a9bd7..d950ae0275 100644
--- a/libraries/networking/src/AddressManager.h
+++ b/libraries/networking/src/AddressManager.h
@@ -98,10 +98,15 @@ private:
bool handleUsername(const QString& lookupString);
bool handleDomainID(const QString& host);
+ void addCurrentAddressToHistory();
+
QString _host;
QUuid _rootPlaceID;
PositionGetter _positionGetter;
OrientationGetter _orientationGetter;
+
+ QList _history;
+ quint64 _lastHistoryAppend = 0;
};
#endif // hifi_AddressManager_h
diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp
index c578015b9f..2ae8968571 100644
--- a/libraries/render-utils/src/Model.cpp
+++ b/libraries/render-utils/src/Model.cpp
@@ -891,6 +891,9 @@ namespace render {
return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, false);
}
}
+ /* template <> const model::MaterialKey& shapeGetMaterialKey(const OpaqueMeshPart::Pointer& payload) {
+ return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex);
+ }*/
}
void Model::setVisibleInScene(bool newValue, std::shared_ptr scene) {
diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp
index f9e78c69bb..777d9466a5 100755
--- a/libraries/render-utils/src/RenderDeferredTask.cpp
+++ b/libraries/render-utils/src/RenderDeferredTask.cpp
@@ -44,7 +44,7 @@ template <> void render::jobRun(const ResolveDeferred& job, const SceneContextPo
RenderDeferredTask::RenderDeferredTask() : Task() {
_jobs.push_back(Job(PrepareDeferred()));
_jobs.push_back(Job(DrawBackground()));
- _jobs.push_back(Job(DrawOpaque()));
+ _jobs.push_back(Job(DrawOpaqueDeferred()));
_jobs.push_back(Job(DrawLight()));
_jobs.push_back(Job(ResetGLState()));
_jobs.push_back(Job(RenderDeferred()));
@@ -78,6 +78,84 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend
+template <> void render::jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
+ PerformanceTimer perfTimer("DrawOpaqueDeferred");
+ assert(renderContext->args);
+ assert(renderContext->args->_viewFrustum);
+
+ // render opaques
+ auto& scene = sceneContext->_scene;
+ auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape());
+ auto& renderDetails = renderContext->args->_details;
+
+ ItemIDsBounds inItems;
+ inItems.reserve(items.size());
+ for (auto id : items) {
+ inItems.emplace_back(ItemIDAndBounds(id));
+ }
+ ItemIDsBounds& renderedItems = inItems;
+
+ renderContext->_numFeedOpaqueItems = renderedItems.size();
+
+ ItemIDsBounds culledItems;
+ culledItems.reserve(inItems.size());
+ if (renderContext->_cullOpaque) {
+ renderDetails.pointTo(RenderDetails::OPAQUE_ITEM);
+ cullItems(sceneContext, renderContext, renderedItems, culledItems);
+ renderDetails.pointTo(RenderDetails::OTHER_ITEM);
+ renderedItems = culledItems;
+ }
+
+ renderContext->_numDrawnOpaqueItems = renderedItems.size();
+
+
+ ItemIDsBounds sortedItems;
+ sortedItems.reserve(culledItems.size());
+ if (renderContext->_sortOpaque) {
+ depthSortItems(sceneContext, renderContext, true, renderedItems, sortedItems); // Sort Front to back opaque items!
+ renderedItems = sortedItems;
+ }
+
+ // ItemIDsBounds sortedItems;
+ /* ItemMaterialBucketMap stateSortedItems;
+ stateSortedItems.allocateStandardMaterialBuckets();
+ if (true) {
+ for (auto& itemIDAndBound : renderedItems) {
+ stateSortedItems.insert(itemIDAndBound.id, scene->getItem(itemIDAndBound.id).getMaterialKey());
+ }
+ }
+*/
+
+ if (renderContext->_renderOpaque) {
+ RenderArgs* args = renderContext->args;
+ gpu::Batch batch;
+ args->_batch = &batch;
+
+ glm::mat4 projMat;
+ Transform viewMat;
+ args->_viewFrustum->evalProjectionMatrix(projMat);
+ args->_viewFrustum->evalViewTransform(viewMat);
+ batch.setProjectionTransform(projMat);
+ batch.setViewTransform(viewMat);
+
+ renderContext->args->_renderMode = RenderArgs::NORMAL_RENDER_MODE;
+ {
+ GLenum buffers[3];
+ int bufferCount = 0;
+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
+ buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
+ batch._glDrawBuffers(bufferCount, buffers);
+ }
+
+ renderItems(sceneContext, renderContext, renderedItems, renderContext->_maxDrawnOpaqueItems);
+
+ args->_context->render((*args->_batch));
+ args->_batch = nullptr;
+ }
+}
+
+
template <> void render::jobRun(const DrawTransparentDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
PerformanceTimer perfTimer("DrawTransparentDeferred");
assert(renderContext->args);
diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h
index 17971dbfac..e2cac53c0d 100755
--- a/libraries/render-utils/src/RenderDeferredTask.h
+++ b/libraries/render-utils/src/RenderDeferredTask.h
@@ -35,6 +35,14 @@ namespace render {
template <> void jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
}
+
+class DrawOpaqueDeferred {
+public:
+};
+namespace render {
+template <> void jobRun(const DrawOpaqueDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
+}
+
class DrawTransparentDeferred {
public:
};
diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp
index 41e36de37b..bfc888ea8a 100755
--- a/libraries/render/src/render/DrawTask.cpp
+++ b/libraries/render/src/render/DrawTask.cpp
@@ -445,3 +445,18 @@ template <> void render::jobRun(const DrawBackground& job, const SceneContextPoi
// Force the context sync
args->_context->syncCache();
}
+
+
+
+void ItemMaterialBucketMap::insert(const ItemID& id, const model::MaterialKey& key) {
+ // Insert the itemID in every bucket where it filters true
+ for (auto& bucket : (*this)) {
+ if (bucket.first.test(key)) {
+ bucket.second.push_back(id);
+ }
+ }
+}
+
+void ItemMaterialBucketMap::allocateStandardMaterialBuckets() {
+ (*this)[model::MaterialFilter::Builder::opaqueDiffuse()];
+}
diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h
index 687287cd56..1f260583f2 100755
--- a/libraries/render/src/render/DrawTask.h
+++ b/libraries/render/src/render/DrawTask.h
@@ -62,6 +62,10 @@ void depthSortItems(const SceneContextPointer& sceneContext, const RenderContext
void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1);
+
+void materialSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
+
+
class DrawOpaque {
public:
};
@@ -101,6 +105,20 @@ public:
};
+
+// A map of ItemIDs allowing to create bucket lists of SHAPE type items which are filtered by their
+// Material
+class ItemMaterialBucketMap : public std::map {
+public:
+
+ ItemMaterialBucketMap() {}
+
+ void insert(const ItemID& id, const model::MaterialKey& key);
+
+ // standard builders allocating the main buckets
+ void allocateStandardMaterialBuckets();
+};
+
}
#endif // hifi_render_Task_h
diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h
index 054fbeb602..8cb29609ba 100644
--- a/libraries/render/src/render/Scene.h
+++ b/libraries/render/src/render/Scene.h
@@ -24,6 +24,8 @@
#include
#include
+#include "model/Material.h"
+
namespace render {
class Context;
@@ -216,6 +218,8 @@ public:
virtual void update(const UpdateFunctorPointer& functor) = 0;
+ virtual const model::MaterialKey getMaterialKey() const = 0;
+
~PayloadInterface() {}
protected:
};
@@ -240,6 +244,9 @@ public:
void render(RenderArgs* args) { _payload->render(args); }
void update(const UpdateFunctorPointer& updateFunctor) { _payload->update(updateFunctor); }
+ // Shape Type Interface
+ const model::MaterialKey& getMaterialKey() const { return _payload->getMaterialKey(); }
+
protected:
PayloadPointer _payload;
ItemKey _key;
@@ -275,16 +282,23 @@ template const ItemKey payloadGetKey(const std::shared_ptr& payload
template const Item::Bound payloadGetBound(const std::shared_ptr& payloadData) { return Item::Bound(); }
template void payloadRender(const std::shared_ptr& payloadData, RenderArgs* args) { }
+// Shape type interface
+template const model::MaterialKey shapeGetMaterialKey(const std::shared_ptr& payloadData) { return model::MaterialKey(); }
+
template class Payload : public Item::PayloadInterface {
public:
typedef std::shared_ptr DataPointer;
typedef UpdateFunctor Updater;
+ virtual void update(const UpdateFunctorPointer& functor) { static_cast(functor.get())->_func((*_data)); }
+
+ // Payload general interface
virtual const ItemKey getKey() const { return payloadGetKey(_data); }
virtual const Item::Bound getBound() const { return payloadGetBound(_data); }
- virtual void render(RenderArgs* args) { payloadRender(_data, args); }
-
- virtual void update(const UpdateFunctorPointer& functor) { static_cast(functor.get())->_func((*_data)); }
+ virtual void render(RenderArgs* args) { payloadRender(_data, args); }
+
+ // Shape Type interface
+ virtual const model::MaterialKey getMaterialKey() const { return shapeGetMaterialKey(_data); }
Payload(const DataPointer& data) : _data(data) {}
protected: