// // Overlay.cpp // interface/src/ui/overlays // // 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 // #include "Overlay.h" #include #include #include "Application.h" static const xColor DEFAULT_OVERLAY_COLOR = { 255, 255, 255 }; static const float DEFAULT_ALPHA = 0.7f; Overlay::Overlay() : _renderItemID(render::Item::INVALID_ITEM_ID), _isLoaded(true), _alpha(DEFAULT_ALPHA), _pulse(1.0f), _pulseMax(0.0f), _pulseMin(0.0f), _pulsePeriod(1.0f), _pulseDirection(1.0f), _lastPulseUpdate(usecTimestampNow()), _alphaPulse(0.0f), _colorPulse(0.0f), _color(DEFAULT_OVERLAY_COLOR), _visible(true), _drawHUDLayer(false), _anchor(NO_ANCHOR) { } Overlay::Overlay(const Overlay* overlay) : _renderItemID(render::Item::INVALID_ITEM_ID), _isLoaded(overlay->_isLoaded), _alpha(overlay->_alpha), _pulse(overlay->_pulse), _pulseMax(overlay->_pulseMax), _pulseMin(overlay->_pulseMin), _pulsePeriod(overlay->_pulsePeriod), _pulseDirection(overlay->_pulseDirection), _lastPulseUpdate(usecTimestampNow()), _alphaPulse(overlay->_alphaPulse), _colorPulse(overlay->_colorPulse), _color(overlay->_color), _visible(overlay->_visible), _drawHUDLayer(overlay->_drawHUDLayer), _anchor(overlay->_anchor) { } Overlay::~Overlay() { } void Overlay::setProperties(const QVariantMap& properties) { bool valid; auto color = xColorFromVariant(properties["color"], valid); if (valid) { _color = color; } if (properties["alpha"].isValid()) { setAlpha(properties["alpha"].toFloat()); } if (properties["pulseMax"].isValid()) { setPulseMax(properties["pulseMax"].toFloat()); } if (properties["pulseMin"].isValid()) { setPulseMin(properties["pulseMin"].toFloat()); } if (properties["pulsePeriod"].isValid()) { setPulsePeriod(properties["pulsePeriod"].toFloat()); } if (properties["alphaPulse"].isValid()) { setAlphaPulse(properties["alphaPulse"].toFloat()); } if (properties["colorPulse"].isValid()) { setColorPulse(properties["colorPulse"].toFloat()); } if (properties["drawHUDLayer"].isValid()) { bool drawHUDLayer = properties["drawHUDLayer"].toBool(); setDrawHUDLayer(drawHUDLayer); } if (properties["visible"].isValid()) { bool visible = properties["visible"].toBool(); setVisible(visible); } if (properties["anchor"].isValid()) { QString property = properties["anchor"].toString(); if (property == "MyAvatar") { setAnchor(MY_AVATAR); } } } QVariant Overlay::getProperty(const QString& property) { if (property == "type") { return QVariant(getType()); } if (property == "color") { return xColorToVariant(_color); } if (property == "alpha") { return _alpha; } if (property == "pulseMax") { return _pulseMax; } if (property == "pulseMin") { return _pulseMin; } if (property == "pulsePeriod") { return _pulsePeriod; } if (property == "alphaPulse") { return _alphaPulse; } if (property == "colorPulse") { return _colorPulse; } if (property == "visible") { return _visible; } if (property == "anchor") { return _anchor == MY_AVATAR ? "MyAvatar" : ""; } return QVariant(); } xColor Overlay::getColor() { if (_colorPulse == 0.0f) { return _color; } float pulseLevel = updatePulse(); xColor result = _color; if (_colorPulse < 0.0f) { result.red *= (1.0f - pulseLevel); result.green *= (1.0f - pulseLevel); result.blue *= (1.0f - pulseLevel); } else { result.red *= pulseLevel; result.green *= pulseLevel; result.blue *= pulseLevel; } return result; } float Overlay::getAlpha() { if (_alphaPulse == 0.0f) { return _alpha; } float pulseLevel = updatePulse(); return (_alphaPulse >= 0.0f) ? _alpha * pulseLevel : _alpha * (1.0f - pulseLevel); } void Overlay::setDrawHUDLayer(bool drawHUDLayer) { if (drawHUDLayer != _drawHUDLayer) { qApp->getOverlays().setOverlayDrawHUDLayer(getOverlayID(), drawHUDLayer); _drawHUDLayer = drawHUDLayer; } } // pulse travels from min to max, then max to min in one period. float Overlay::updatePulse() { if (_pulsePeriod <= 0.0f) { return _pulse; } quint64 now = usecTimestampNow(); quint64 elapsedUSecs = (now - _lastPulseUpdate); float elapsedSeconds = (float)elapsedUSecs / (float)USECS_PER_SECOND; float elapsedPeriods = elapsedSeconds / _pulsePeriod; // we can safely remove any "full" periods, since those just rotate us back // to our final pulse level elapsedPeriods = fmod(elapsedPeriods, 1.0f); _lastPulseUpdate = now; float pulseDistance = (_pulseMax - _pulseMin); float pulseDistancePerPeriod = pulseDistance * 2.0f; float pulseDelta = _pulseDirection * pulseDistancePerPeriod * elapsedPeriods; float newPulse = _pulse + pulseDelta; float limit = (_pulseDirection > 0.0f) ? _pulseMax : _pulseMin; float passedLimit = (_pulseDirection > 0.0f) ? (newPulse >= limit) : (newPulse <= limit); if (passedLimit) { float pulseDeltaToLimit = newPulse - limit; float pulseDeltaFromLimitBack = pulseDelta - pulseDeltaToLimit; pulseDelta = -pulseDeltaFromLimitBack; _pulseDirection *= -1.0f; } _pulse += pulseDelta; return _pulse; } bool Overlay::addToScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) { _renderItemID = scene->allocateID(); transaction.resetItem(_renderItemID, std::make_shared(overlay)); return true; } void Overlay::removeFromScene(Overlay::Pointer overlay, const render::ScenePointer& scene, render::Transaction& transaction) { transaction.removeItem(_renderItemID); render::Item::clearID(_renderItemID); } QScriptValue OverlayIDtoScriptValue(QScriptEngine* engine, const OverlayID& id) { return quuidToScriptValue(engine, id); } void OverlayIDfromScriptValue(const QScriptValue &object, OverlayID& id) { quuidFromScriptValue(object, id); } QVector qVectorOverlayIDFromScriptValue(const QScriptValue& array) { if (!array.isArray()) { return QVector(); } QVector newVector; int length = array.property("length").toInteger(); newVector.reserve(length); for (int i = 0; i < length; i++) { newVector << OverlayID(array.property(i).toString()); } return newVector; }