From 1c9269fc8d7333ef20c5cbca084eed7d540ae9e8 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 6 Jan 2015 17:43:19 +0000 Subject: [PATCH] Add simple OpenEXR save/load support using tinyexr * Thanks to https://github.com/syoyo/tinyexr for the load and save code! --- renderdoc/Makefile | 1 + renderdoc/api/replay/replay_enums.h | 1 + renderdoc/core/core.cpp | 18 ++++++++++ renderdoc/core/core.h | 3 ++ renderdoc/core/image_viewer.cpp | 22 +++++++++++- renderdoc/renderdoc.vcxproj | 4 ++- renderdoc/renderdoc.vcxproj.filters | 9 +++++ renderdoc/replay/replay_renderer.cpp | 36 ++++++++++++++----- renderdocui/Interop/Enums.cs | 1 + .../Windows/Dialogs/TextureSaveDialog.cs | 4 ++- 10 files changed, 87 insertions(+), 12 deletions(-) diff --git a/renderdoc/Makefile b/renderdoc/Makefile index 354e744a1..51cb90944 100644 --- a/renderdoc/Makefile +++ b/renderdoc/Makefile @@ -33,6 +33,7 @@ os/os_specific.o \ 3rdparty/jpeg-compressor/jpge.o \ 3rdparty/lz4/lz4.o \ 3rdparty/stb/stb_impl.o \ +3rdparty/tinyexr/tinyexr.o \ driver/gl/gl_common.o \ driver/gl/gl_driver.o \ driver/gl/gl_manager.o \ diff --git a/renderdoc/api/replay/replay_enums.h b/renderdoc/api/replay/replay_enums.h index d6844e615..e4a9edf0b 100644 --- a/renderdoc/api/replay/replay_enums.h +++ b/renderdoc/api/replay/replay_enums.h @@ -136,6 +136,7 @@ enum FileType eFileType_BMP, eFileType_TGA, eFileType_HDR, + eFileType_EXR, }; enum AlphaMapping diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index 436fa4b23..b6c2ade5c 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -36,6 +36,21 @@ #include "stb/stb_image.h" #include "common/dds_readwrite.h" +// not provided by tinyexr, just do by hand +bool is_exr_file(FILE *f) +{ + FileIO::fseek64(f, 0, SEEK_SET); + + const uint32_t openexr_magic = MAKE_FOURCC(0x76, 0x2f, 0x31, 0x01); + + uint32_t magic = 0; + FileIO::fread(&magic, sizeof(magic), 1, f); + + FileIO::fseek64(f, 0, SEEK_SET); + + return magic == openexr_magic; +} + template<> string ToStrHelper::Get(const RDCDriver &el) { @@ -480,6 +495,9 @@ ReplayCreateStatus RenderDoc::FillInitParams(const char *logFile, RDCDriver &dri if(is_dds_file(f)) ret = x = y = comp = 1; + if(is_exr_file(f)) + ret = x = y = comp = 1; + FileIO::fclose(f); if(ret == 1 && x > 0 && y > 0 && comp > 0) diff --git a/renderdoc/core/core.h b/renderdoc/core/core.h index 6b2268a7d..9d01ccf26 100644 --- a/renderdoc/core/core.h +++ b/renderdoc/core/core.h @@ -46,6 +46,9 @@ class Chunk; #include "os/os_specific.h" #include "common/threading.h" +// not provided by tinyexr, just do by hand +bool is_exr_file(FILE *f); + struct ICrashHandler { virtual ~ICrashHandler() {} diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 8d7153579..ecf573664 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -27,6 +27,7 @@ #include "replay/type_helpers.h" #include "stb/stb_image.h" +#include "tinyexr/tinyexr.h" #include "common/dds_readwrite.h" class ImageViewer : public IReplayDriver @@ -194,7 +195,26 @@ ReplayCreateStatus IMG_CreateReplayDevice(const char *logfile, IReplayDriver **d bool dds = false; - if(stbi_is_hdr_from_file(f)) + if(is_exr_file(f)) + { + texDetails.format = rgba32_float; + + FileIO::fseek64(f, 0, SEEK_SET); + + const char *err = NULL; + + int ret = LoadEXRFP((float **)&data, (int *)&texDetails.width, (int *)&texDetails.height, f, &err); + datasize = texDetails.width*texDetails.height*4*sizeof(float); + + // could be an unsupported form of EXR, like deep image or other + if(ret != 0) + { + if(data) free(data); + RDCERR("EXR file detected, but couldn't load with LoadEXR %d: '%s'", ret, err); + return eReplayCreate_APIUnsupported; + } + } + else if(stbi_is_hdr_from_file(f)) { texDetails.format = rgba32_float; diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index 0c7714a54..111ea093c 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -213,6 +213,7 @@ + @@ -286,6 +287,7 @@ + @@ -382,4 +384,4 @@ - + \ No newline at end of file diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index d433ad725..748ea601c 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -88,6 +88,9 @@ {ce0b860f-38b7-48af-b49d-7dcb23378f82} + + {aadadb32-abbc-45b3-8f86-026eed994ba9} + @@ -309,6 +312,9 @@ Common\Strings + + 3rdparty\tinyexr + @@ -536,6 +542,9 @@ Common\Strings + + 3rdparty\tinyexr + diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp index 287aabca3..38455ea99 100644 --- a/renderdoc/replay/replay_renderer.cpp +++ b/renderdoc/replay/replay_renderer.cpp @@ -38,6 +38,7 @@ #include "jpeg-compressor/jpge.h" #include "stb/stb_image.h" #include "stb/stb_image_write.h" +#include "tinyexr/tinyexr.h" #include "common/dds_readwrite.h" float ConvertComponent(ResourceFormat fmt, byte *data) @@ -561,8 +562,8 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) downcast = true; // for DDS don't downcast, for non-HDR always downcast if we're not already RGBA8 unorm - // for HDR we can convert from most regular types as well as 10.10.10.2 and 11.11.10 - if((sd.destType != eFileType_DDS && sd.destType != eFileType_HDR && + // for HDR&EXR we can convert from most regular types as well as 10.10.10.2 and 11.11.10 + if((sd.destType != eFileType_DDS && sd.destType != eFileType_HDR && sd.destType != eFileType_EXR && (td.format.compByteWidth != 1 || td.format.compType != eCompType_UNorm) ) || downcast || @@ -945,9 +946,9 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) delete[] jpgdst; } - else if(sd.destType == eFileType_HDR) + else if(sd.destType == eFileType_HDR || sd.destType == eFileType_EXR) { - float *fldata = new float[td.width*td.height*3]; + float *fldata = new float[td.width*td.height*4]; byte *srcData = subdata[0]; @@ -958,6 +959,7 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) float r = 0.0f; float g = 0.0f; float b = 0.0f; + float a = 1.0f; if(td.format.special && td.format.specialFormat == eSpecial_R10G10B10A2) { @@ -968,6 +970,7 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) r = vec.x; g = vec.y; b = vec.z; + a = vec.w; srcData += 4; } @@ -980,6 +983,7 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) r = vec.x; g = vec.y; b = vec.z; + a = 1.0f; srcData += 4; } @@ -991,18 +995,32 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) g = ConvertComponent(td.format, srcData + td.format.compByteWidth*1); if(td.format.compCount >= 3) b = ConvertComponent(td.format, srcData + td.format.compByteWidth*2); + if(td.format.compCount >= 4) + a = ConvertComponent(td.format, srcData + td.format.compByteWidth*3); srcData += td.format.compCount * td.format.compByteWidth; } - fldata[(y*td.width + x) * 3 + 0] = r; - fldata[(y*td.width + x) * 3 + 1] = g; - fldata[(y*td.width + x) * 3 + 2] = b; + fldata[(y*td.width + x) * 4 + 0] = r; + fldata[(y*td.width + x) * 4 + 1] = g; + fldata[(y*td.width + x) * 4 + 2] = b; + fldata[(y*td.width + x) * 4 + 3] = a; } } - int ret = stbi_write_hdr_to_file(f, td.width, td.height, 3, fldata); - success = (ret != 0); + if(sd.destType == eFileType_HDR) + { + int ret = stbi_write_hdr_to_file(f, td.width, td.height, 4, fldata); + success = (ret != 0); + } + else if(sd.destType == eFileType_EXR) + { + const char *err = NULL; + int ret = SaveEXRFP(fldata, (int)td.width, (int)td.height, f, &err); + success = (ret == 0); + if(!success) + RDCERR("Error saving EXR file %d: '%s'", ret, err); + } delete[] fldata; } diff --git a/renderdocui/Interop/Enums.cs b/renderdocui/Interop/Enums.cs index 75a664985..829238154 100644 --- a/renderdocui/Interop/Enums.cs +++ b/renderdocui/Interop/Enums.cs @@ -138,6 +138,7 @@ namespace renderdoc BMP, TGA, HDR, + EXR, }; public enum AlphaMapping diff --git a/renderdocui/Windows/Dialogs/TextureSaveDialog.cs b/renderdocui/Windows/Dialogs/TextureSaveDialog.cs index 4a102125d..33a2f6ff1 100644 --- a/renderdocui/Windows/Dialogs/TextureSaveDialog.cs +++ b/renderdocui/Windows/Dialogs/TextureSaveDialog.cs @@ -150,7 +150,9 @@ namespace renderdocui.Windows.Dialogs jpegCompression.Enabled = (saveData.destType == FileType.JPG); - alphaLDRGroup.Visible = (saveData.destType != FileType.HDR && saveData.destType != FileType.DDS); + alphaLDRGroup.Visible = (saveData.destType != FileType.HDR && + saveData.destType != FileType.EXR && + saveData.destType != FileType.DDS); bool noAlphaFormat = (saveData.destType == FileType.BMP || saveData.destType == FileType.JPG);