diff options
author | RunitaiLinden <davep@lindenlab.com> | 2024-03-08 12:01:20 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-08 12:01:20 -0600 |
commit | c1bde75768e1374d4f094936d52ed29f6f5d3cba (patch) | |
tree | eddbe1b79490e27e63e05fa36b4175bea1e02fc9 /indra/newview/llreflectionmapmanager.cpp | |
parent | cca461647f4569fb57e35679dd86a863f5d52702 (diff) |
HDRI Local Preview (#953)
* #926 WIP - HDRI import prototype v0
* #926 WIP -- add OpenEXR to autobuild.xml
* #926 WIP -- Add OpenEXR cmake
* #926 WIP -- Attempt at using OpenEXR autobuild package and don't hard code .exr file to load
* #926 Unmangle autobuild.xml and get dll's in the right place (thanks, Caladbolg!)
* implement mac shared libs plumbing for OpenEXR for secondlife/viewer#926
* Fix Xcode/clang compile error regarding new[]/delete[] mismatch
* #926 HDRI Preview finishing touches.
- Full ACES when HDRI is enabled
- Fix for probes getting stuck paused
- Add exposure and rotation controls
---------
Co-authored-by: Brad Linden <brad@lindenlab.com>
Diffstat (limited to 'indra/newview/llreflectionmapmanager.cpp')
-rw-r--r-- | indra/newview/llreflectionmapmanager.cpp | 131 |
1 files changed, 129 insertions, 2 deletions
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index ce389a5cad..f9c5421866 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -38,6 +38,126 @@ #include "llviewercontrol.h" #include "llenvironment.h" #include "llstartup.h" +#include "llviewermenufile.h" +#include "llnotificationsutil.h" + + +// load an OpenEXR image from a file +#define IMATH_HALF_NO_LOOKUP_TABLE 1 +#include <ImfInputFile.h> +#include <ImfArray.h> +#include <ImfHeader.h> +#include <ImfFrameBuffer.h> +#include <iostream> + +LLPointer<LLImageGL> gEXRImage; + +void load_exr(const std::string& filename) +{ + // reset reflection maps when previewing a new HDRI + gPipeline.mReflectionMapManager.reset(); + gPipeline.mReflectionMapManager.initReflectionMaps(); + + try { + Imf::InputFile file(filename.c_str()); + Imath::Box2i dw = file.header().dataWindow(); + int width = dw.max.x - dw.min.x + 1; + int height = dw.max.y - dw.min.y + 1; + + Imf::Array2D<Imath::half> rPixels; + Imf::Array2D<Imath::half> gPixels; + Imf::Array2D<Imath::half> bPixels; + + rPixels.resizeErase(height, width); + gPixels.resizeErase(height, width); + bPixels.resizeErase(height, width); + + Imf::FrameBuffer frameBuffer; + + frameBuffer.insert("R", // name + Imf::Slice(Imf::HALF, // type + (char*)(&rPixels[0][0] - // base + dw.min.x - + dw.min.y * width), + sizeof(rPixels[0][0]) * 1, // xStride + sizeof(rPixels[0][0]) * width, // yStride + 1, 1, // x/y sampling + 0.0)); // fillValue + + frameBuffer.insert("G", // name + Imf::Slice(Imf::HALF, // type + (char*)(&gPixels[0][0] - // base + dw.min.x - + dw.min.y * width), + sizeof(gPixels[0][0]) * 1, // xStride + sizeof(gPixels[0][0]) * width, // yStride + 1, 1, // x/y sampling + 0.0)); // fillValue + + frameBuffer.insert("B", // name + Imf::Slice(Imf::HALF, // type + (char*)(&bPixels[0][0] - // base + dw.min.x - + dw.min.y * width), + sizeof(bPixels[0][0]) * 1, // xStride + sizeof(bPixels[0][0]) * width, // yStride + 1, 1, // x/y sampling + FLT_MAX)); // fillValue + + file.setFrameBuffer(frameBuffer); + file.readPixels(dw.min.y, dw.max.y); + + 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); + + std::vector<F32> data(width * height * 3); + for (int i = 0; i < width * height; ++i) + { + data[i * 3 + 0] = rPixels[i / width][i % width]; + data[i * 3 + 1] = gPixels[i / width][i % width]; + data[i * 3 + 2] = bPixels[i / width][i % width]; + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data.data()); + + glGenerateMipmap(GL_TEXTURE_2D); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + } + catch (const std::exception& e) { + LLSD notif_args; + notif_args["WHAT"] = filename; + notif_args["REASON"] = e.what(); + LLNotificationsUtil::add("CannotLoad", notif_args); + return; + } +} + +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; @@ -133,6 +253,11 @@ void LLReflectionMapManager::update() return; } + if (mPaused && gFrameTimeSeconds > mResumeTime) + { + resume(); + } + initReflectionMaps(); if (!mRenderTarget.isComplete()) @@ -831,9 +956,10 @@ void LLReflectionMapManager::reset() mReset = true; } -void LLReflectionMapManager::pause() +void LLReflectionMapManager::pause(F32 duration) { mPaused = true; + mResumeTime = gFrameTimeSeconds + duration; } void LLReflectionMapManager::resume() @@ -1283,6 +1409,8 @@ void LLReflectionMapManager::initReflectionMaps() if (mTexture.isNull() || mReflectionProbeCount != count || mReset) { + gEXRImage = nullptr; + mReset = false; mReflectionProbeCount = count; mProbeResolution = nhpo2(llclamp(gSavedSettings.getU32("RenderReflectionProbeResolution"), (U32)64, (U32)512)); @@ -1340,7 +1468,6 @@ void LLReflectionMapManager::initReflectionMaps() mDefaultProbe->mComplete = default_complete; touch_default_probe(mDefaultProbe); - } if (mVertexBuffer.isNull()) |