summaryrefslogtreecommitdiff
path: root/indra/newview/llreflectionmapmanager.cpp
diff options
context:
space:
mode:
authorRunitaiLinden <davep@lindenlab.com>2024-03-08 12:01:20 -0600
committerGitHub <noreply@github.com>2024-03-08 12:01:20 -0600
commitc1bde75768e1374d4f094936d52ed29f6f5d3cba (patch)
treeeddbe1b79490e27e63e05fa36b4175bea1e02fc9 /indra/newview/llreflectionmapmanager.cpp
parentcca461647f4569fb57e35679dd86a863f5d52702 (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.cpp131
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())