HifiExperimentsfix debug build from 745b036981 year agoHistory
451 lines · 15.2 KB · C++
RawDownload
////  FadeEffectJobs.cpp //  Created by Olivier Prat on 07/07/2017.//  Copyright 2017 High Fidelity, Inc.//  Copyright 2024 Overte e.V.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html//#include "FadeEffectJobs.h"#include "render/Logging.h"#include "render/TransitionStage.h" #include "FadeObjectParams.shared.slh" #include <NumericalConstants.h>#include <Interpolate.h>#include <gpu/Context.h> #include <QJsonArray> #include <PathUtils.h> #define FADE_MIN_SCALE  0.001#define FADE_MAX_SCALE  10000.0#define FADE_MAX_SPEED  50.f inline float parameterToValuePow(float parameter, const double minValue, const double maxOverMinValue) {    return (float)(minValue * pow(maxOverMinValue, double(parameter)));} inline float valueToParameterPow(float value, const double minValue, const double maxOverMinValue) {    return (float)(log(double(value) / minValue) / log(maxOverMinValue));} void FadeEditJob::configure(const Config& config) {    _isEditEnabled = config.editFade;    _editedCategory =  std::min<int>((int)TransitionType::TYPE_COUNT, config.editedCategory);} void FadeEditJob::run(const render::RenderContextPointer& renderContext, Output& output) {    auto scene = renderContext->_scene;    output = render::Item::INVALID_ITEM_ID;     if (_isEditEnabled) {        static const std::string selectionName("TransitionEdit");        auto scene = renderContext->_scene;        if (!scene->isSelectionEmpty(selectionName)) {            auto selection = scene->getSelection(selectionName);            auto editedItem = selection.getItems().front();            output = editedItem;            render::Transaction transaction;            bool hasTransaction{ false };             if (editedItem != _editedItem && render::Item::isValidID(_editedItem)) {                // Remove transition from previously edited item as we've changed edited item                hasTransaction = true;                transaction.removeTransitionFromItem(_editedItem);            }            _editedItem = editedItem;             if (render::Item::isValidID(_editedItem)) {                auto transitionType = (TransitionType)_editedCategory;                transaction.queryTransitionOnItem(_editedItem, [transitionType, scene](render::ItemID id, const render::Transition* transition) {                    if (transition == nullptr || transition->isFinished || transition->eventType != transitionType) {                        // Relaunch transition                        render::Transaction transaction;                        transaction.resetTransitionOnItem(id, transitionType);                        scene->enqueueTransaction(transaction);                    }                });                hasTransaction = true;            }             if (hasTransaction) {                scene->enqueueTransaction(transaction);            }        } else if (render::Item::isValidID(_editedItem)) {            // Remove transition from previously edited item as we've disabled fade edition            render::Transaction transaction;            transaction.removeTransitionFromItem(_editedItem);            scene->enqueueTransaction(transaction);            _editedItem = render::Item::INVALID_ITEM_ID;        }    }    else if (render::Item::isValidID(_editedItem)) {        // Remove transition from previously edited item as we've disabled fade edition        render::Transaction transaction;        transaction.removeTransitionFromItem(_editedItem);        scene->enqueueTransaction(transaction);        _editedItem = render::Item::INVALID_ITEM_ID;    }} FadeConfig::FadeConfig() {} void FadeConfig::setDuration(float value) {    props.duration = value;    emit dirty();} float FadeConfig::getDuration() const {     return props.duration;} void FadeConfig::setBaseSizeX(float value) {    props.baseSizeInv.x = 1.0f / parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE/ FADE_MIN_SCALE);    emit dirty();} float FadeConfig::getBaseSizeX() const {     return valueToParameterPow(1.0f / props.baseSizeInv.x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);} void FadeConfig::setBaseSizeY(float value) {    props.baseSizeInv.y = 1.0f / parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);    emit dirty();} float FadeConfig::getBaseSizeY() const {    return valueToParameterPow(1.0f / props.baseSizeInv.y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);} void FadeConfig::setBaseSizeZ(float value) {    props.baseSizeInv.z = 1.0f / parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);    emit dirty();} float FadeConfig::getBaseSizeZ() const {    return valueToParameterPow(1.0f / props.baseSizeInv.z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);} void FadeConfig::setBaseLevel(float value) {    props.baseLevel = value;    emit dirty();} void FadeConfig::setInverted(bool value) {    props.inverted = value;    emit dirty();} bool FadeConfig::isInverted() const {     return props.inverted;} void FadeConfig::setNoiseSizeX(float value) {    props.noiseSizeInv.x = 1.0f / parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);    emit dirty();} float FadeConfig::getNoiseSizeX() const {    return valueToParameterPow(1.0f / props.noiseSizeInv.x, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);} void FadeConfig::setNoiseSizeY(float value) {    props.noiseSizeInv.y = 1.0f / parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);    emit dirty();} float FadeConfig::getNoiseSizeY() const {    return valueToParameterPow(1.0f / props.noiseSizeInv.y, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);} void FadeConfig::setNoiseSizeZ(float value) {    props.noiseSizeInv.z = 1.0f / parameterToValuePow(value, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);    emit dirty();} float FadeConfig::getNoiseSizeZ() const {    return valueToParameterPow(1.0f / props.noiseSizeInv.z, FADE_MIN_SCALE, FADE_MAX_SCALE / FADE_MIN_SCALE);} void FadeConfig::setNoiseLevel(float value) {    props.noiseLevel = value;    emit dirty();} void FadeConfig::setNoiseSpeedX(float value) {    props.noiseSpeed.x = powf(value, 3.f)*FADE_MAX_SPEED;    emit dirty();} float FadeConfig::getNoiseSpeedX() const {    return powf(props.noiseSpeed.x / FADE_MAX_SPEED, 1.f / 3.f);} void FadeConfig::setNoiseSpeedY(float value) {    props.noiseSpeed.y = powf(value, 3.f)*FADE_MAX_SPEED;    emit dirty();} float FadeConfig::getNoiseSpeedY() const {    return powf(props.noiseSpeed.y / FADE_MAX_SPEED, 1.f / 3.f);} void FadeConfig::setNoiseSpeedZ(float value) {    props.noiseSpeed.z = powf(value, 3.f)*FADE_MAX_SPEED;    emit dirty();} float FadeConfig::getNoiseSpeedZ() const {    return powf(props.noiseSpeed.z / FADE_MAX_SPEED, 1.f / 3.f);} void FadeConfig::setEdgeWidth(float value) {    props.edgeWidth = value * value;    emit dirty();} float FadeConfig::getEdgeWidth() const {     return sqrtf(props.edgeWidth);} void FadeConfig::setEdgeInnerColor(const QColor& value) {    props.innerEdgeColor.r = value.redF();    props.innerEdgeColor.g = value.greenF();    props.innerEdgeColor.b = value.blueF();    emit dirty();} QColor FadeConfig::getEdgeInnerColor() const {    QColor color;    color.setRedF(props.innerEdgeColor.r);    color.setGreenF(props.innerEdgeColor.g);    color.setBlueF(props.innerEdgeColor.b);    color.setAlphaF(1.0f);    return color;} void FadeConfig::setEdgeInnerIntensity(float value) {    props.innerEdgeColor.a = value;    emit dirty();} void FadeConfig::setEdgeOuterColor(const QColor& value) {    props.outerEdgeColor.r = value.redF();    props.outerEdgeColor.g = value.greenF();    props.outerEdgeColor.b = value.blueF();    emit dirty();} QColor FadeConfig::getEdgeOuterColor() const {    QColor color;    color.setRedF(props.outerEdgeColor.r);    color.setGreenF(props.outerEdgeColor.g);    color.setBlueF(props.outerEdgeColor.b);    color.setAlphaF(1.0f);    return color;} void FadeConfig::setEdgeOuterIntensity(float value) {    props.outerEdgeColor.a = value;    emit dirty();} void FadeConfig::setTiming(int value) {    assert(value < static_cast<int>(FadeTiming::TIMING_COUNT));    props.timing = (FadeTiming)value;    emit dirty();} FadeJob::FadeJob() {    _previousTime = usecTimestampNow();} void FadeJob::configure(const Config& config) {    _editedFadeProperties = config.props;} void FadeJob::run(const render::RenderContextPointer& renderContext, const Input& input) {    Config* jobConfig = static_cast<Config*>(renderContext->jobConfig.get());     auto scene = renderContext->args->_scene;    auto transitionStage = scene->getStage<render::TransitionStage>();    uint64_t now = usecTimestampNow();    const double deltaTime = (int64_t(now) - int64_t(_previousTime)) / double(USECS_PER_SECOND);    render::Transaction transaction;    bool isFirstItem = true;    bool hasTransaction = false;     // And now update fade effect    for (auto transitionId : *transitionStage) {        auto& state = transitionStage->editElement(transitionId);#ifdef DEBUG        auto& item = scene->getItem(state.itemId);        assert(item.getTransitionId() == transitionId);#endif        if (update(renderContext->args, *jobConfig, scene, transaction, state, deltaTime, input)) {            hasTransaction = true;        }        if (isFirstItem && (state.threshold != jobConfig->threshold)) {            jobConfig->setProperty("threshold", state.threshold);            isFirstItem = false;        }    }    _previousTime = now;    if (hasTransaction) {        scene->enqueueTransaction(transaction);    }} bool FadeJob::update(RenderArgs* args,                     const Config& config,                     const render::ScenePointer& scene,                     render::Transaction& transaction,                     render::Transition& transition,                     const double deltaTime,                     const render::ItemID editedItemID) const {    auto item = scene->getItemSafe(transition.itemId);    if (!item.exist()) {        return false;    }     bool hasParamsBuffer = transition.paramsBuffer._size == sizeof(FadeObjectParams);    FadeProperties fadeProperties;    if (transition.itemId == editedItemID) {        fadeProperties = _editedFadeProperties;    } else {        fadeProperties = hasParamsBuffer ? transition.fadeProperties : item.getFadeProperties(transition.eventType);    }    const double eventDuration = (double)fadeProperties.duration;    const FadeTiming timing = fadeProperties.timing;     auto aabb = item.getBound(args);    if (render::Item::isValidID(transition.boundItemId)) {        auto boundItem = scene->getItemSafe(transition.boundItemId);        if (boundItem.exist()) {            aabb = boundItem.getBound(args);        }    }    auto& dimensions = aabb.getDimensions();     assert(timing < FadeTiming::TIMING_COUNT);     transition.noiseOffset = aabb.calcCenter();    transition.baseInvSize = fadeProperties.baseSizeInv;     switch (transition.eventType) {    case TransitionType::ELEMENT_ENTER_DOMAIN:    case TransitionType::ELEMENT_LEAVE_DOMAIN:    {        transition.threshold = computeElementEnterRatio(transition.time, eventDuration, timing);        transition.baseOffset = transition.noiseOffset;        transition.isFinished += (transition.threshold >= 1.0f) & 1;        if (transition.eventType == TransitionType::ELEMENT_ENTER_DOMAIN) {            transition.threshold = 1.0f - transition.threshold;        }    }    break;     case TransitionType::BUBBLE_ISECT_OWNER:    {        transition.threshold = 0.5f;        transition.baseOffset = transition.noiseOffset;    }    break;     case TransitionType::BUBBLE_ISECT_TRESPASSER:    {        transition.threshold = 0.5f;        transition.baseOffset = transition.noiseOffset;    }    break;     case TransitionType::USER_ENTER_DOMAIN:    case TransitionType::USER_LEAVE_DOMAIN:    {        transition.threshold = computeElementEnterRatio(transition.time, eventDuration, timing);        transition.baseOffset = transition.noiseOffset - dimensions.y / 2.f;        transition.baseInvSize.y = 1.f / dimensions.y;        transition.isFinished += (transition.threshold >= 1.0f) & 1;        if (transition.eventType == TransitionType::USER_LEAVE_DOMAIN) {            transition.threshold = 1.f - transition.threshold;        }    }    break;     case TransitionType::AVATAR_CHANGE:        break;     default:        assert(false);    }     transition.noiseOffset += fadeProperties.noiseSpeed * (float)transition.time;    if (config.manualFade) {        transition.threshold = config.manualThreshold;    }    transition.threshold = std::max(0.f, std::min(1.f, transition.threshold));    transition.threshold = (transition.threshold - 0.5f);    transition.threshold *= 1.0f + (fadeProperties.edgeWidth + std::max(0.0f, (fadeProperties.noiseLevel + fadeProperties.baseLevel) * 0.5f - 0.5f));    transition.threshold += 0.5f;    transition.time += deltaTime;     if (!hasParamsBuffer) {        static_assert(sizeof(transition.paramsBuffer) == sizeof(gpu::StructBuffer<FadeObjectParams>),                      "Assuming gpu::StructBuffer is a helper class for gpu::BufferView");        transition.paramsBuffer = gpu::StructBuffer<FadeObjectParams>();    }     auto& params = static_cast<gpu::StructBuffer<FadeObjectParams>&>(transition.paramsBuffer).edit();    if (!hasParamsBuffer) {        params.noiseOffsetAndInverted.w = fadeProperties.inverted;        params.baseInvSizeAndLevel.w = fadeProperties.baseLevel;        params.noiseInvSizeAndLevel = vec4(fadeProperties.noiseSizeInv, fadeProperties.noiseLevel);        params.innerEdgeColor = fadeProperties.innerEdgeColor;        params.outerEdgeColor = fadeProperties.outerEdgeColor;        params.edgeWidthInv = 1.0f / fadeProperties.edgeWidth;         transition.fadeProperties = fadeProperties;    }     params.noiseOffsetAndInverted = vec4(transition.noiseOffset, params.noiseOffsetAndInverted.w);    params.baseOffsetAndThreshold = vec4(transition.baseOffset, transition.threshold);    params.baseInvSizeAndLevel = vec4(transition.baseInvSize, params.baseInvSizeAndLevel.w);     // If the transition is finished for more than a number of frames (here 1), garbage collect it.    if (transition.isFinished > 1) {        transaction.removeTransitionFromItem(transition.itemId);        return true;    }    return false;} float FadeJob::computeElementEnterRatio(double time, const double period, FadeTiming timing) {    assert(period > 0.0);    float fadeAlpha = 1.0f;    const double INV_FADE_PERIOD = 1.0 / period;    double fraction = time * INV_FADE_PERIOD;    fraction = std::max(fraction, 0.0);    if (fraction < 1.0) {        switch (timing) {        default:            fadeAlpha = (float)fraction;            break;        case FadeTiming::EASE_IN:            fadeAlpha = (float)(fraction*fraction*fraction);            break;        case FadeTiming::EASE_OUT:            fadeAlpha = 1.f - (float)fraction;            fadeAlpha = 1.f- fadeAlpha*fadeAlpha*fadeAlpha;            break;        case FadeTiming::EASE_IN_OUT:            fadeAlpha = (float)(fraction*fraction*fraction*(fraction*(fraction * 6 - 15) + 10));            break;        }    }    return fadeAlpha;}