diff --git a/renderdoc/api/replay/control_types.h b/renderdoc/api/replay/control_types.h index bafb15599..9def7502b 100644 --- a/renderdoc/api/replay/control_types.h +++ b/renderdoc/api/replay/control_types.h @@ -178,6 +178,8 @@ struct TextureSave // and file format doesn't support saving all slices, only // slice 0 is saved } slice; + + int channelExtract; // for formats without an alpha channel, define how it should be // mapped. Only available for uncompressed simple formats, done diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp index 1bf51ba79..bd78a6f2c 100644 --- a/renderdoc/replay/replay_renderer.cpp +++ b/renderdoc/replay/replay_renderer.cpp @@ -490,6 +490,10 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) sd.slice.slicesAsGrid = false; } + // can't extract a channel that's not in the source texture + if(sd.channelExtract >= 0 && (uint32_t)sd.channelExtract >= td.format.compCount) + sd.channelExtract = -1; + sd.slice.sliceGridWidth = RDCMAX(sd.slice.sliceGridWidth, 1); // store sample count so we know how many 'slices' is one real slice @@ -876,6 +880,25 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) } int numComps = td.format.compCount; + + // if we want a grayscale image of one channel, splat it across all channels + // and set alpha to full + if(sd.channelExtract >= 0 && td.format.compByteWidth == 1 && (uint32_t)sd.channelExtract < td.format.compCount) + { + for(uint32_t y=0; y < td.height; y++) + { + for(uint32_t x=0; x < td.width; x++) + { + subdata[0][ ( y * td.width + x ) * 4 + 0 ] = subdata[0][ ( y * td.width + x ) * 4 + sd.channelExtract ]; + if(td.format.compCount >= 2) + subdata[0][ ( y * td.width + x ) * 4 + 1 ] = subdata[0][ ( y * td.width + x ) * 4 + sd.channelExtract ]; + if(td.format.compCount >= 3) + subdata[0][ ( y * td.width + x ) * 4 + 2 ] = subdata[0][ ( y * td.width + x ) * 4 + sd.channelExtract ]; + if(td.format.compCount >= 4) + subdata[0][ ( y * td.width + x ) * 4 + 3 ] = 255; + } + } + } // handle formats that don't support alpha if(numComps == 4 && (sd.destType == eFileType_BMP || sd.destType == eFileType_JPG) ) @@ -1074,6 +1097,23 @@ bool ReplayRenderer::SaveTexture(const TextureSave &saveData, const char *path) a = RDCMAX(a, 0.0f); } + if(sd.channelExtract == 0) + { + g = b = r; a = 1.0f; + } + if(sd.channelExtract == 1) + { + r = b = g; a = 1.0f; + } + if(sd.channelExtract == 2) + { + r = g = b; a = 1.0f; + } + if(sd.channelExtract == 3) + { + r = g = b = a; a = 1.0f; + } + fldata[(y*td.width + x) * 4 + 0] = r; fldata[(y*td.width + x) * 4 + 1] = g; fldata[(y*td.width + x) * 4 + 2] = b; diff --git a/renderdocui/Interop/FetchInfo.cs b/renderdocui/Interop/FetchInfo.cs index 0b7f4b31f..96aad3687 100644 --- a/renderdocui/Interop/FetchInfo.cs +++ b/renderdocui/Interop/FetchInfo.cs @@ -487,6 +487,8 @@ namespace renderdoc [CustomMarshalAs(CustomUnmanagedType.CustomClass)] public SliceMapping slice = new SliceMapping(); + public int channelExtract = -1; + public AlphaMapping alpha = AlphaMapping.Discard; public FloatVector alphaCol = new FloatVector(0.666f, 0.666f, 0.666f); public FloatVector alphaColSecondary = new FloatVector(0.333f, 0.333f, 0.333f); diff --git a/renderdocui/Windows/TextureViewer.cs b/renderdocui/Windows/TextureViewer.cs index 800058110..c2b03ab94 100644 --- a/renderdocui/Windows/TextureViewer.cs +++ b/renderdocui/Windows/TextureViewer.cs @@ -3399,6 +3399,17 @@ namespace renderdocui.Windows m_SaveDialog.saveData.id = m_TexDisplay.texid; m_SaveDialog.saveData.slice.sliceIndex = (int)m_TexDisplay.sliceFace; m_SaveDialog.saveData.mip = (int)m_TexDisplay.mip; + + m_SaveDialog.saveData.channelExtract = -1; + if (m_TexDisplay.Red && !m_TexDisplay.Green && !m_TexDisplay.Blue && !m_TexDisplay.Alpha) + m_SaveDialog.saveData.channelExtract = 0; + if (!m_TexDisplay.Red && m_TexDisplay.Green && !m_TexDisplay.Blue && !m_TexDisplay.Alpha) + m_SaveDialog.saveData.channelExtract = 1; + if (!m_TexDisplay.Red && !m_TexDisplay.Green && m_TexDisplay.Blue && !m_TexDisplay.Alpha) + m_SaveDialog.saveData.channelExtract = 2; + if (!m_TexDisplay.Red && !m_TexDisplay.Green && !m_TexDisplay.Blue && m_TexDisplay.Alpha) + m_SaveDialog.saveData.channelExtract = 3; + m_SaveDialog.saveData.comp.blackPoint = m_TexDisplay.rangemin; m_SaveDialog.saveData.comp.whitePoint = m_TexDisplay.rangemax; m_SaveDialog.saveData.alphaCol = m_TexDisplay.lightBackgroundColour;