Skip to content
Snippets Groups Projects
llreflectionmapmanager.cpp 46.6 KiB
Newer Older
/**
 * @file llreflectionmapmanager.cpp
 * @brief LLReflectionMapManager class implementation
 *
 * $LicenseInfo:firstyear=2022&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2022, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llreflectionmapmanager.h"
Rye Mutt's avatar
Rye Mutt committed

#include <vector>

#include "llspatialpartition.h"
#include "llviewerregion.h"
#include "pipeline.h"
#include "llviewershadermgr.h"
#include "llviewercontrol.h"
#include "llviewermenufile.h"
#include "llnotificationsutil.h"

Rye Mutt's avatar
Rye Mutt committed
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4702) // compiler complains unreachable code
#endif
Rye Mutt's avatar
Rye Mutt committed
#define TINYEXR_USE_MINIZ 0
#include "zlib.h"
#define TINYEXR_IMPLEMENTATION
#include "tinyexr/tinyexr.h"
Rye Mutt's avatar
Rye Mutt committed
#if LL_WINDOWS
#pragma warning (pop)
#endif

LLPointer<LLImageGL> gEXRImage;

void load_exr(const std::string& filename)
{
    // reset reflection maps when previewing a new HDRI
    gPipeline.mReflectionMapManager.reset();
    gPipeline.mReflectionMapManager.initReflectionMaps();

Rye Mutt's avatar
Rye Mutt committed
    float* out; // width * height * RGBA
    int width;
    int height;
    const char* err = NULL; // or nullptr in C++11

    int ret =  LoadEXRWithLayer(&out, &width, &height, filename.c_str(), /* layername */ nullptr, &err);
Rye Mutt's avatar
Rye Mutt committed
    if (ret == TINYEXR_SUCCESS)
Rye Mutt's avatar
Rye Mutt committed
    {
        U32 texName = 0;
        LLImageGL::generateTextures(1, &texName);

        gEXRImage = new LLImageGL(texName, 4, GL_TEXTURE_2D, GL_RGB16F, GL_RGB16F, GL_FLOAT, LLTexUnit::TAM_CLAMP);
        gEXRImage->setHasMipMaps(TRUE);
        gEXRImage->setUseMipMaps(TRUE);
        gEXRImage->setFilteringOption(LLTexUnit::TFO_TRILINEAR);

        gGL.getTexUnit(0)->bind(gEXRImage);

Rye Mutt's avatar
Rye Mutt committed
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGBA, GL_FLOAT, out);
Rye Mutt's avatar
Rye Mutt committed
        free(out); // release memory of image data

        glGenerateMipmap(GL_TEXTURE_2D);

        gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
Rye Mutt's avatar
Rye Mutt committed

    }
Rye Mutt's avatar
Rye Mutt committed
    else
Rye Mutt's avatar
Rye Mutt committed
    {
        LLSD notif_args;
        notif_args["WHAT"] = filename;
        notif_args["REASON"] = "Unknown";
Rye Mutt's avatar
Rye Mutt committed
        if (err)
Rye Mutt's avatar
Rye Mutt committed
        {
            notif_args["REASON"] = std::string(err);
Rye Mutt's avatar
Rye Mutt committed
            FreeEXRErrorMessage(err); // release memory of error message.
        }
        LLNotificationsUtil::add("CannotLoad", notif_args);
    }
}

void hdri_preview()
{
    LLFilePickerReplyThread::startPicker(
        [](const std::vector<std::string>& filenames, LLFilePicker::ELoadFilter load_filter, LLFilePicker::ESaveFilter save_filter)
        {
            if (LLAppViewer::instance()->quitRequested())
            {
                return;
            }
            if (filenames.size() > 0)
            {
                load_exr(filenames[0]);
            }
        },
        LLFilePicker::FFLOAD_HDRI,
        true);
}

extern BOOL gCubeSnapshot;
extern BOOL gTeleportDisplay;

// get the next highest power of two of v (or v if v is already a power of two)
//defined in llvertexbuffer.cpp
extern U32 nhpo2(U32 v);

static void touch_default_probe(LLReflectionMap* probe)
{
    if (LLViewerCamera::getInstance())
    {
        LLVector3 origin = LLViewerCamera::getInstance()->getOrigin();
        origin.mV[2] += 64.f;
LLReflectionMapManager::LLReflectionMapManager()
{
    initCubeFree();
}

void LLReflectionMapManager::initCubeFree()
    // start at 1 because index 0 is reserved for mDefaultProbe
    for (int i = 1; i < LL_MAX_REFLECTION_PROBE_COUNT; ++i)
    bool operator()(const LLPointer<LLReflectionMap>& lhs, const LLPointer<LLReflectionMap>& rhs)
        return lhs->mDistance < rhs->mDistance;
static F32 update_score(LLReflectionMap* p)
{
    return gFrameTimeSeconds - p->mLastUpdateTime  - p->mDistance*0.1f;
}

// return true if a is higher priority for an update than b
static bool check_priority(LLReflectionMap* a, LLReflectionMap* b)
{
    if (a->mCubeIndex == -1)
    { // not a candidate for updating
        return false;
    }
    else if (b->mCubeIndex == -1)
    { // b is not a candidate for updating, a is higher priority by default
        return true;
    }
    else if (!a->mComplete && !b->mComplete)
    { //neither probe is complete, use distance
        return a->mDistance < b->mDistance;
    }
    else if (a->mComplete && b->mComplete)
    { //both probes are complete, use update_score metric
        return update_score(a) > update_score(b);
    // a or b is not complete,
    if (sUpdateCount % 3 == 0)
    { // every third update, allow complete probes to cut in line in front of non-complete probes to avoid spammy probe generators from deadlocking scheduler (SL-20258))
        return !b->mComplete;
    }

    // prioritize incomplete probe
Loading
Loading full blame...