diff --git a/docs/FAQ.aml b/docs/FAQ.aml index 48901f1b5..38c0c4818 100644 --- a/docs/FAQ.aml +++ b/docs/FAQ.aml @@ -218,5 +218,38 @@ +
+ Gamma display of linear data, or "Why doesn't my texture look right?" + + + Gamma/SRGB correctness is a rather painful subject. If we could all just agree to store everything + in 32bit float data we could probably do away with it. Until that time we have to worry about + displaying textures while making sure to respect SRGB. + + + For texture formats that explicitly specify that they contain SRGB data this isn't a problem and + everything works smoothly. Note that RenderDoc shows picked texel values in linear float format, + so if you pick a pixel that is 0.5, 0.5, 0.5, the actual bytes might be stored as say 186, 186, 186. + + + For other textures it's more difficult - for starters they may actually contain SRGB data but the + correction is handled by shaders so there's no markup. Or indeed the app may not be gamma-correct so the + data is SRGB but uncorrected. If we display these textures in a technically correct way, such that the + data is not over or under gamma-corrected, the result often looks 'wrong' or unintuitively different + from expected. + + + Nothing is actually wrong here except perhaps that when visualising linear data it is often more convenient + to "overcorrect" such that the data is perceptually linear. A good example to use is a normal map: + The classic deep blue of (127,127,255) flat normals is technically incorrect as everyone is used to + visualising these textures in programs that display the data as if it were SRGB (which is the convention for + normal images that do not represent vectors). + + + You can override this behaviour on any texture that isn't listed as explicitly SRGB with the gamma (γ) + button - toggle this off and the overcorrection will be disabled. + + +
diff --git a/docs/Windows/TextureViewer.aml b/docs/Windows/TextureViewer.aml index 3f254d622..c6d1da432 100644 --- a/docs/Windows/TextureViewer.aml +++ b/docs/Windows/TextureViewer.aml @@ -215,6 +215,17 @@ and delete an one with the button. + + + γ + Gamma display of Linear data + + + A proper explanation of this is available in the + . In short, linear data is 'overcorrected' to + look as expected, but this behaviour can be overridden + + @@ -226,8 +237,8 @@ the semi-transparent sections more obvious. With these two controls you can either choose a checkerboard pattern or open a colour picker to choose a solid colour . - The currently enabled mode will be highlighted. + diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index 8fefe6265..b57f97aa7 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -1396,6 +1396,7 @@ void D3D11DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, ui texDisplay.Red = texDisplay.Green = texDisplay.Blue = texDisplay.Alpha = true; texDisplay.HDRMul = -1.0f; + texDisplay.linearDisplayAsGamma = true; texDisplay.mip = mip; texDisplay.CustomShader = ResourceId(); texDisplay.sliceFace = sliceFace; @@ -2048,6 +2049,7 @@ ResourceId D3D11DebugManager::ApplyCustomShader(ResourceId shader, ResourceId te disp.texid = texid; disp.lightBackgroundColour = disp.darkBackgroundColour = FloatVector(0,0,0,0); disp.HDRMul = -1.0f; + disp.linearDisplayAsGamma = true; disp.mip = mip; disp.overlay = eTexOverlay_None; disp.rangemin = 0.0f; diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index 495a85e72..19c0dbf16 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -3464,7 +3464,7 @@ bool D3D11DebugManager::RenderTexture(TextureDisplay cfg) pixelData.OutputDisplayFormat |= TEXDISPLAY_SINT_TEX; srvOffset = 20; } - if(!IsSRGBFormat(details.texFmt)) + if(!IsSRGBFormat(details.texFmt) && cfg.linearDisplayAsGamma) { pixelData.OutputDisplayFormat |= TEXDISPLAY_GAMMA_CURVE; } diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 9039821fd..702fe0ec6 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -198,6 +198,7 @@ void GLReplay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sl texDisplay.Red = texDisplay.Green = texDisplay.Blue = texDisplay.Alpha = true; texDisplay.HDRMul = -1.0f; + texDisplay.linearDisplayAsGamma = true; texDisplay.mip = mip; texDisplay.CustomShader = ResourceId(); texDisplay.sliceFace = sliceFace; diff --git a/renderdoc/replay/control_types.h b/renderdoc/replay/control_types.h index b559a7765..0f67760ec 100644 --- a/renderdoc/replay/control_types.h +++ b/renderdoc/replay/control_types.h @@ -60,6 +60,7 @@ struct TextureDisplay float scale; bool32 Red, Green, Blue, Alpha; float HDRMul; + bool32 linearDisplayAsGamma; ResourceId CustomShader; uint32_t mip; uint32_t sliceFace; diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index 886d1e0c9..477bb795c 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -361,6 +361,7 @@ bool ReplayOutput::Display() disp.Red = disp.Green = disp.Blue = true; disp.Alpha = false; disp.HDRMul = -1.0f; + disp.linearDisplayAsGamma = true; disp.mip = 0; disp.CustomShader = ResourceId(); disp.texid = m_pDevice->GetLiveID(m_Thumbnails[i].texture); diff --git a/renderdocui/Interop/FetchInfo.cs b/renderdocui/Interop/FetchInfo.cs index 76bec0a0d..cd80059fd 100644 --- a/renderdocui/Interop/FetchInfo.cs +++ b/renderdocui/Interop/FetchInfo.cs @@ -414,6 +414,7 @@ namespace renderdoc public float scale = 1.0f; public bool Red = true, Green = true, Blue = true, Alpha = false; public float HDRMul = -1.0f; + public bool linearDisplayAsGamma = true; public ResourceId CustomShader = ResourceId.Null; public UInt32 mip = 0; public UInt32 sliceFace = 0; diff --git a/renderdocui/Windows/TextureViewer.Designer.cs b/renderdocui/Windows/TextureViewer.Designer.cs index c18217581..08bc46de9 100644 --- a/renderdocui/Windows/TextureViewer.Designer.cs +++ b/renderdocui/Windows/TextureViewer.Designer.cs @@ -120,25 +120,27 @@ this.debugPixel = new System.Windows.Forms.ToolStripButton(); this.texListShow = new System.Windows.Forms.ToolStripButton(); this.texlistContainer = new System.Windows.Forms.TableLayoutPanel(); - this.textureList = new renderdocui.Controls.TextureListBox(); this.texturefilter = new System.Windows.Forms.ComboBox(); this.label1 = new System.Windows.Forms.Label(); this.clearTexFilter = new System.Windows.Forms.Button(); this.renderToolstripContainer = new System.Windows.Forms.ToolStripContainer(); this.renderScrollTable = new System.Windows.Forms.TableLayoutPanel(); - this.renderContainer = new renderdocui.Controls.NoScrollPanel(); - this.render = new renderdocui.Controls.NoScrollPanel(); this.renderVScroll = new System.Windows.Forms.VScrollBar(); this.renderHScroll = new System.Windows.Forms.HScrollBar(); this.pixelContextPanel = new System.Windows.Forms.TableLayoutPanel(); - this.pixelContext = new renderdocui.Controls.NoScrollPanel(); this.debugPixelContext = new System.Windows.Forms.Button(); this.tabContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); this.closeTab = new System.Windows.Forms.ToolStripMenuItem(); this.closeOtherTabs = new System.Windows.Forms.ToolStripMenuItem(); this.closeTabsToRight = new System.Windows.Forms.ToolStripMenuItem(); + this.gammaDisplay = new System.Windows.Forms.ToolStripButton(); + this.gammaSeparator = new System.Windows.Forms.ToolStripSeparator(); + this.textureList = new renderdocui.Controls.TextureListBox(); this.texPanel = new renderdocui.Controls.ThumbnailStrip(); this.rtPanel = new renderdocui.Controls.ThumbnailStrip(); + this.pixelContext = new renderdocui.Controls.NoScrollPanel(); + this.renderContainer = new renderdocui.Controls.NoScrollPanel(); + this.render = new renderdocui.Controls.NoScrollPanel(); this.rangeHistogram = new renderdocui.Controls.RangeHistogram(); subSep = new System.Windows.Forms.ToolStripSeparator(); toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); @@ -161,9 +163,9 @@ this.renderToolstripContainer.ContentPanel.SuspendLayout(); this.renderToolstripContainer.SuspendLayout(); this.renderScrollTable.SuspendLayout(); - this.renderContainer.SuspendLayout(); this.pixelContextPanel.SuspendLayout(); this.tabContextMenu.SuspendLayout(); + this.renderContainer.SuspendLayout(); this.SuspendLayout(); // // subSep @@ -517,7 +519,7 @@ this.overlayStrip.Location = new System.Drawing.Point(216, 50); this.overlayStrip.Margin = new System.Windows.Forms.Padding(0, 0, 12, 0); this.overlayStrip.Name = "overlayStrip"; - this.overlayStrip.Size = new System.Drawing.Size(204, 25); + this.overlayStrip.Size = new System.Drawing.Size(171, 25); this.overlayStrip.TabIndex = 3; // // toolStripLabel5 @@ -553,7 +555,7 @@ this.mipLevel, this.sliceFaceLabel, this.sliceFace}); - this.subStrip.Location = new System.Drawing.Point(604, 0); + this.subStrip.Location = new System.Drawing.Point(633, 0); this.subStrip.Margin = new System.Windows.Forms.Padding(0, 0, 12, 0); this.subStrip.Name = "subStrip"; this.subStrip.Size = new System.Drawing.Size(400, 25); @@ -604,7 +606,7 @@ this.autoFit, this.reset01, this.visualiseRange}); - this.rangeStrip.Location = new System.Drawing.Point(432, 50); + this.rangeStrip.Location = new System.Drawing.Point(399, 50); this.rangeStrip.Margin = new System.Windows.Forms.Padding(0, 0, 12, 0); this.rangeStrip.Name = "rangeStrip"; this.rangeStrip.Size = new System.Drawing.Size(237, 25); @@ -686,11 +688,13 @@ this.customEdit, this.customDelete, this.backcolorPick, - this.checkerBack}); + this.checkerBack, + this.gammaSeparator, + this.gammaDisplay}); this.channelStrip.Location = new System.Drawing.Point(0, 0); this.channelStrip.Margin = new System.Windows.Forms.Padding(0, 0, 12, 0); this.channelStrip.Name = "channelStrip"; - this.channelStrip.Size = new System.Drawing.Size(592, 25); + this.channelStrip.Size = new System.Drawing.Size(621, 25); this.channelStrip.TabIndex = 1; // // channels @@ -867,7 +871,7 @@ this.statusbar.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.Flow; this.statusbar.Location = new System.Drawing.Point(0, 0); this.statusbar.Name = "statusbar"; - this.statusbar.Size = new System.Drawing.Size(420, 18); + this.statusbar.Size = new System.Drawing.Size(420, 19); this.statusbar.SizingGrip = false; this.statusbar.TabIndex = 0; // @@ -980,20 +984,6 @@ this.texlistContainer.Size = new System.Drawing.Size(136, 260); this.texlistContainer.TabIndex = 1; // - // textureList - // - this.texlistContainer.SetColumnSpan(this.textureList, 2); - this.textureList.Dock = System.Windows.Forms.DockStyle.Fill; - this.textureList.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.textureList.IntegralHeight = false; - this.textureList.ItemHeight = 16; - this.textureList.Location = new System.Drawing.Point(3, 50); - this.textureList.Name = "textureList"; - this.textureList.SelectionMode = System.Windows.Forms.SelectionMode.None; - this.textureList.Size = new System.Drawing.Size(130, 207); - this.textureList.TabIndex = 0; - this.textureList.MouseUp += new System.Windows.Forms.MouseEventHandler(this.textureList_MouseUp); - // // texturefilter // this.texturefilter.Dock = System.Windows.Forms.DockStyle.Fill; @@ -1043,7 +1033,7 @@ // renderToolstripContainer.ContentPanel // this.renderToolstripContainer.ContentPanel.Controls.Add(this.renderScrollTable); - this.renderToolstripContainer.ContentPanel.Size = new System.Drawing.Size(420, 248); + this.renderToolstripContainer.ContentPanel.Size = new System.Drawing.Size(420, 247); this.renderToolstripContainer.LeftToolStripPanelVisible = false; this.renderToolstripContainer.Location = new System.Drawing.Point(299, 87); this.renderToolstripContainer.Name = "renderToolstripContainer"; @@ -1068,43 +1058,16 @@ this.renderScrollTable.RowCount = 2; this.renderScrollTable.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.renderScrollTable.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.renderScrollTable.Size = new System.Drawing.Size(420, 248); + this.renderScrollTable.Size = new System.Drawing.Size(420, 247); this.renderScrollTable.TabIndex = 2; // - // renderContainer - // - this.renderContainer.BackColor = System.Drawing.Color.Maroon; - this.renderContainer.Controls.Add(this.render); - this.renderContainer.Dock = System.Windows.Forms.DockStyle.Fill; - this.renderContainer.Location = new System.Drawing.Point(0, 0); - this.renderContainer.Margin = new System.Windows.Forms.Padding(0); - this.renderContainer.Name = "renderContainer"; - this.renderContainer.Size = new System.Drawing.Size(404, 232); - this.renderContainer.TabIndex = 1; - // - // render - // - this.render.BackColor = System.Drawing.Color.Black; - this.render.Dock = System.Windows.Forms.DockStyle.Fill; - this.render.Location = new System.Drawing.Point(0, 0); - this.render.Name = "render"; - this.render.Size = new System.Drawing.Size(404, 232); - this.render.TabIndex = 0; - this.render.Paint += new System.Windows.Forms.PaintEventHandler(this.render_Paint); - this.render.Layout += new System.Windows.Forms.LayoutEventHandler(this.render_Layout); - this.render.MouseClick += new System.Windows.Forms.MouseEventHandler(this.render_MouseClick); - this.render.MouseDown += new System.Windows.Forms.MouseEventHandler(this.render_MouseClick); - this.render.MouseLeave += new System.EventHandler(this.render_MouseLeave); - this.render.MouseMove += new System.Windows.Forms.MouseEventHandler(this.render_MouseMove); - this.render.MouseUp += new System.Windows.Forms.MouseEventHandler(this.render_MouseUp); - // // renderVScroll // this.renderVScroll.Dock = System.Windows.Forms.DockStyle.Right; this.renderVScroll.Enabled = false; this.renderVScroll.Location = new System.Drawing.Point(404, 0); this.renderVScroll.Name = "renderVScroll"; - this.renderVScroll.Size = new System.Drawing.Size(16, 232); + this.renderVScroll.Size = new System.Drawing.Size(16, 231); this.renderVScroll.TabIndex = 2; this.renderVScroll.Scroll += new System.Windows.Forms.ScrollEventHandler(this.renderVScroll_Scroll); // @@ -1112,7 +1075,7 @@ // this.renderHScroll.Dock = System.Windows.Forms.DockStyle.Bottom; this.renderHScroll.Enabled = false; - this.renderHScroll.Location = new System.Drawing.Point(0, 232); + this.renderHScroll.Location = new System.Drawing.Point(0, 231); this.renderHScroll.Name = "renderHScroll"; this.renderHScroll.Size = new System.Drawing.Size(404, 16); this.renderHScroll.TabIndex = 3; @@ -1132,16 +1095,6 @@ this.pixelContextPanel.Size = new System.Drawing.Size(108, 127); this.pixelContextPanel.TabIndex = 11; // - // pixelContext - // - this.pixelContext.BackColor = System.Drawing.Color.Transparent; - this.pixelContext.Dock = System.Windows.Forms.DockStyle.Fill; - this.pixelContext.Location = new System.Drawing.Point(3, 3); - this.pixelContext.Name = "pixelContext"; - this.pixelContext.Size = new System.Drawing.Size(102, 92); - this.pixelContext.TabIndex = 6; - this.pixelContext.Paint += new System.Windows.Forms.PaintEventHandler(this.pixelContext_Paint); - // // debugPixelContext // this.debugPixelContext.Anchor = System.Windows.Forms.AnchorStyles.Bottom; @@ -1185,6 +1138,40 @@ this.closeTabsToRight.Text = "Close tabs to right"; this.closeTabsToRight.Click += new System.EventHandler(this.closeTabsToRight_Click); // + // gammaDisplay + // + this.gammaDisplay.Checked = true; + this.gammaDisplay.CheckOnClick = true; + this.gammaDisplay.CheckState = System.Windows.Forms.CheckState.Checked; + this.gammaDisplay.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.gammaDisplay.Image = ((System.Drawing.Image)(resources.GetObject("gammaDisplay.Image"))); + this.gammaDisplay.ImageTransparentColor = System.Drawing.Color.Magenta; + this.gammaDisplay.Name = "gammaDisplay"; + this.gammaDisplay.Size = new System.Drawing.Size(23, 22); + this.gammaDisplay.Text = "γ"; + this.gammaDisplay.ToolTipText = "Override display of linear data in gamma space\r\n\r\nSee FAQ on \"Gamma display of li" + + "near data\""; + this.gammaDisplay.CheckedChanged += new System.EventHandler(this.updateChannelsHandler); + // + // gammaSeparator + // + this.gammaSeparator.Name = "gammaSeparator"; + this.gammaSeparator.Size = new System.Drawing.Size(6, 25); + // + // textureList + // + this.texlistContainer.SetColumnSpan(this.textureList, 2); + this.textureList.Dock = System.Windows.Forms.DockStyle.Fill; + this.textureList.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; + this.textureList.IntegralHeight = false; + this.textureList.ItemHeight = 16; + this.textureList.Location = new System.Drawing.Point(3, 50); + this.textureList.Name = "textureList"; + this.textureList.SelectionMode = System.Windows.Forms.SelectionMode.None; + this.textureList.Size = new System.Drawing.Size(130, 207); + this.textureList.TabIndex = 0; + this.textureList.MouseUp += new System.Windows.Forms.MouseEventHandler(this.textureList_MouseUp); + // // texPanel // this.texPanel.AutoScroll = true; @@ -1210,6 +1197,43 @@ this.rtPanel.TabIndex = 2; this.rtPanel.MouseClick += new System.Windows.Forms.MouseEventHandler(this.thumbsLayout_MouseClick); // + // pixelContext + // + this.pixelContext.BackColor = System.Drawing.Color.Transparent; + this.pixelContext.Dock = System.Windows.Forms.DockStyle.Fill; + this.pixelContext.Location = new System.Drawing.Point(3, 3); + this.pixelContext.Name = "pixelContext"; + this.pixelContext.Size = new System.Drawing.Size(102, 92); + this.pixelContext.TabIndex = 6; + this.pixelContext.Paint += new System.Windows.Forms.PaintEventHandler(this.pixelContext_Paint); + // + // renderContainer + // + this.renderContainer.BackColor = System.Drawing.Color.Maroon; + this.renderContainer.Controls.Add(this.render); + this.renderContainer.Dock = System.Windows.Forms.DockStyle.Fill; + this.renderContainer.Location = new System.Drawing.Point(0, 0); + this.renderContainer.Margin = new System.Windows.Forms.Padding(0); + this.renderContainer.Name = "renderContainer"; + this.renderContainer.Size = new System.Drawing.Size(404, 231); + this.renderContainer.TabIndex = 1; + // + // render + // + this.render.BackColor = System.Drawing.Color.Black; + this.render.Dock = System.Windows.Forms.DockStyle.Fill; + this.render.Location = new System.Drawing.Point(0, 0); + this.render.Name = "render"; + this.render.Size = new System.Drawing.Size(404, 231); + this.render.TabIndex = 0; + this.render.Paint += new System.Windows.Forms.PaintEventHandler(this.render_Paint); + this.render.Layout += new System.Windows.Forms.LayoutEventHandler(this.render_Layout); + this.render.MouseClick += new System.Windows.Forms.MouseEventHandler(this.render_MouseClick); + this.render.MouseDown += new System.Windows.Forms.MouseEventHandler(this.render_MouseClick); + this.render.MouseLeave += new System.EventHandler(this.render_MouseLeave); + this.render.MouseMove += new System.Windows.Forms.MouseEventHandler(this.render_MouseMove); + this.render.MouseUp += new System.Windows.Forms.MouseEventHandler(this.render_MouseUp); + // // rangeHistogram // this.rangeHistogram.BackColor = System.Drawing.SystemColors.GradientActiveCaption; @@ -1275,10 +1299,10 @@ this.renderToolstripContainer.ResumeLayout(false); this.renderToolstripContainer.PerformLayout(); this.renderScrollTable.ResumeLayout(false); - this.renderContainer.ResumeLayout(false); this.pixelContextPanel.ResumeLayout(false); this.pixelContextPanel.PerformLayout(); this.tabContextMenu.ResumeLayout(false); + this.renderContainer.ResumeLayout(false); this.ResumeLayout(false); this.PerformLayout(); @@ -1377,6 +1401,8 @@ private System.Windows.Forms.ToolStripButton customCreate; private System.Windows.Forms.ToolStripButton customDelete; private System.Windows.Forms.ToolStripButton customEdit; + private System.Windows.Forms.ToolStripButton gammaDisplay; + private System.Windows.Forms.ToolStripSeparator gammaSeparator; } } \ No newline at end of file diff --git a/renderdocui/Windows/TextureViewer.cs b/renderdocui/Windows/TextureViewer.cs index 1f70314f0..5667fdb66 100644 --- a/renderdocui/Windows/TextureViewer.cs +++ b/renderdocui/Windows/TextureViewer.cs @@ -1437,6 +1437,13 @@ namespace renderdocui.Windows channelStrip.SuspendLayout(); + if (tex != null && !tex.format.srgbCorrected) + gammaDisplay.Enabled = true; + else + gammaDisplay.Enabled = false; + + m_TexDisplay.linearDisplayAsGamma = gammaDisplay.Checked; + if (tex != null && (tex.creationFlags & TextureCreationFlags.DSV) > 0 && (string)channels.SelectedItem != "Custom") { diff --git a/renderdocui/Windows/TextureViewer.resx b/renderdocui/Windows/TextureViewer.resx index 62c62fb2e..0d13e7f8b 100644 --- a/renderdocui/Windows/TextureViewer.resx +++ b/renderdocui/Windows/TextureViewer.resx @@ -163,61 +163,76 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI - ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9 - HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN - rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K - TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx - oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8 - 7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI - xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX - LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd - KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI - ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9 - HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN - rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K - TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx - oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8 - 7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI - xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX - LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd - KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI - ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9 - HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN - rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K - TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx - oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8 - 7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI - xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX - LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd - KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg== iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIISURBVDhPpZP7S1NxGMbPPxKaXVUkMEq8IpKUCoY/hGgI - ymqkDYYXcCjDZOANURSjCNGFQUTsl4GXVMxKk62YU4fXQpaIlygHQxBRH8/zwvyaIAYe+HLgnPN8nue9 - HA3nvDTq63oW/jm13XOwvPTB3DYFY5MH+bXfcN8ygfTSMSSXfESicQDxBqdYHwH29g9w2tnZ3UcguIvN - rR3417exuBJE5N1n/wfwLgXEOc38Bc6xNRHb+/y4nm49G0Bnit2zf9H6bkliE/jKuYxrd6oVgDWfjB+K - TWeKMyrGEVfowITvD9re/9ABVQrAhh0HHK+ZselMMaN/mvwtDb+aVqkA7HYIwIj3ysfluPTorJnP6Ezx - oHsD1s5ZXEktUwCOioB5f1CEPR9+wTG6iuiserTo8dkwng7HT/R+XUPF8xlcTjErAOdMcW6NW8STiwG8 - 7vej8oUPN/PsEv3t8Ao0TZP3T1u8uJRkUgAuSYHtO97oLxmXd5t9Ho8aPTK+GzntqNfrLm2fFoihwYOI - xGIF4KjoGBLzY1OrF9k6OOFxnwDC4wxIMX1G0pMhgVyMNyoA13PAtS7OrJk1PrC69LUdQWxuF6IybHrX - LRI7JrtZdoDAo1XmbjMyD+tjSXxGcXRmnYg5ttD9QuxDhN0uUgDOmbvNTpPOJaGAo2K36cyaGZvOFIfd - KlSA8/zRh9ABIDUG+1JpAAAAAElFTkSuQmCC + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg== + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG + YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9 + 0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw + bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc + VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9 + c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32 + Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo + mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+ + kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D + TgDQASA1MVpwzwAAAABJRU5ErkJggg==