Ejemplo n.º 1
0
        private void UI_OnTextureSelectionChanged(bool newdraw)
        {
            FetchTexture tex = CurrentTexture;

            // reset high-water mark
            m_HighWaterStatusLength = 0;

            if (tex == null) return;

            bool newtex = (m_TexDisplay.texid != tex.ID);

            // save settings for this current texture
            if (m_Core.Config.TextureViewer_PerTexSettings)
            {
                if (!m_TextureSettings.ContainsKey(m_TexDisplay.texid))
                    m_TextureSettings.Add(m_TexDisplay.texid, new TexSettings());

                m_TextureSettings[m_TexDisplay.texid].r = customRed.Checked;
                m_TextureSettings[m_TexDisplay.texid].g = customGreen.Checked;
                m_TextureSettings[m_TexDisplay.texid].b = customBlue.Checked;
                m_TextureSettings[m_TexDisplay.texid].a = customAlpha.Checked;

                m_TextureSettings[m_TexDisplay.texid].displayType = channels.SelectedIndex;
                m_TextureSettings[m_TexDisplay.texid].customShader = customShader.Text;

                m_TextureSettings[m_TexDisplay.texid].depth = depthDisplay.Checked;
                m_TextureSettings[m_TexDisplay.texid].stencil = stencilDisplay.Checked;

                m_TextureSettings[m_TexDisplay.texid].mip = mipLevel.SelectedIndex;
                m_TextureSettings[m_TexDisplay.texid].slice = sliceFace.SelectedIndex;

                m_TextureSettings[m_TexDisplay.texid].minrange = rangeHistogram.BlackPoint;
                m_TextureSettings[m_TexDisplay.texid].maxrange = rangeHistogram.WhitePoint;

                m_TextureSettings[m_TexDisplay.texid].typeHint = m_Following.GetTypeHint(m_Core);
            }

            m_TexDisplay.texid = tex.ID;

            // interpret the texture according to the currently following type.
            if(!CurrentTextureIsLocked)
                m_TexDisplay.typeHint = m_Following.GetTypeHint(m_Core);
            else
                m_TexDisplay.typeHint = FormatComponentType.None;

            // if there is no such type or it isn't being followed, use the last seen interpretation
            if (m_TexDisplay.typeHint == FormatComponentType.None && m_TextureSettings.ContainsKey(m_TexDisplay.texid))
                m_TexDisplay.typeHint = m_TextureSettings[m_TexDisplay.texid].typeHint;

            // try to maintain the pan in the new texture. If the new texture
            // is approx an integer multiple of the old texture, just changing
            // the scale will keep everything the same. This is useful for
            // downsample chains and things where you're flipping back and forth
            // between overlapping textures, but even in the non-integer case
            // pan will be kept approximately the same.
            PointF curSize = new PointF((float)CurrentTexture.width, (float)CurrentTexture.height);
            float curArea = curSize.Area();
            float prevArea = m_PrevSize.Area();

            if (prevArea > 0.0f)
            {
                float prevX = m_TexDisplay.offx;
                float prevY = m_TexDisplay.offy;
                float prevScale = m_TexDisplay.scale;

                // allow slight difference in aspect ratio for rounding errors
                // in downscales (e.g. 1680x1050 -> 840x525 -> 420x262 in the
                // last downscale the ratios are 1.6 and 1.603053435).
                if (Math.Abs(curSize.Aspect() - m_PrevSize.Aspect()) < 0.01f)
                {
                    m_TexDisplay.scale *= m_PrevSize.X / curSize.X;
                    CurrentZoomValue = m_TexDisplay.scale;
                }
                else
                {
                    // this scale factor is arbitrary really, only intention is to have
                    // integer scales come out precisely, other 'similar' sizes will be
                    // similar ish
                    float scaleFactor = (float)(Math.Sqrt(curArea) / Math.Sqrt(prevArea));

                    m_TexDisplay.offx = prevX * scaleFactor;
                    m_TexDisplay.offy = prevY * scaleFactor;
                }
            }

            m_PrevSize = curSize;

            // refresh scroll position
            ScrollPosition = ScrollPosition;

            UI_UpdateStatusText();

            mipLevel.Items.Clear();

            m_TexDisplay.mip = 0;
            m_TexDisplay.sliceFace = 0;

            bool usemipsettings = true;
            bool useslicesettings = true;

            if (tex.msSamp > 1)
            {
                for (int i = 0; i < tex.msSamp; i++)
                    mipLevel.Items.Add(String.Format("Sample {0}", i));

                // add an option to display unweighted average resolved value,
                // to get an idea of how the samples average
                if(tex.format.compType != FormatComponentType.UInt &&
                    tex.format.compType != FormatComponentType.SInt &&
                    tex.format.compType != FormatComponentType.Depth &&
                    (tex.creationFlags & TextureCreationFlags.DSV) == 0)
                    mipLevel.Items.Add("Average val");

                mipLevelLabel.Text = "Sample";

                mipLevel.SelectedIndex = 0;
            }
            else
            {
                for (int i = 0; i < tex.mips; i++)
                    mipLevel.Items.Add(i + " - " + Math.Max(1, tex.width >> i) + "x" + Math.Max(1, tex.height >> i));

                mipLevelLabel.Text = "Mip";

                int highestMip = -1;

                // only switch to the selected mip for outputs, and when changing drawcall
                if (!CurrentTextureIsLocked && m_Following.Type != FollowType.ReadOnly && newdraw)
                    highestMip = m_Following.GetHighestMip(m_Core);

                // assuming we get a valid mip for the highest mip, only switch to it
                // if we've selected a new texture, or if it's different than the last mip.
                // This prevents the case where the user has clicked on another mip and
                // we don't want to snap their view back when stepping between events with the
                // same mip used. But it does mean that if they are stepping between
                // events with different mips used, then we will update in that case.
                if (highestMip >= 0 && (newtex || highestMip != prevHighestMip))
                {
                    usemipsettings = false;
                    mipLevel.SelectedIndex = Helpers.Clamp(highestMip, 0, (int)tex.mips - 1);
                }

                if (mipLevel.SelectedIndex == -1)
                    mipLevel.SelectedIndex = Helpers.Clamp(prevHighestMip, 0, (int)tex.mips - 1);

                prevHighestMip = highestMip;
            }

            if (tex.mips == 1 && tex.msSamp <= 1)
            {
                mipLevel.Enabled = false;
            }
            else
            {
                mipLevel.Enabled = true;
            }

            sliceFace.Items.Clear();

            if (tex.numSubresources == tex.mips && tex.depth <= 1)
            {
                sliceFace.Enabled = false;
            }
            else
            {
                sliceFace.Enabled = true;

                sliceFace.Visible = sliceFaceLabel.Visible = true;

                String[] cubeFaces = { "X+", "X-", "Y+", "Y-", "Z+", "Z-" };

                UInt32 numSlices = (Math.Max(1, tex.depth) * tex.numSubresources) / tex.mips;

                // for 3D textures, display the number of slices at this mip
                if(tex.depth > 1)
                    numSlices = Math.Max(1, tex.depth >> (int)mipLevel.SelectedIndex);

                for (UInt32 i = 0; i < numSlices; i++)
                {
                    if (tex.cubemap)
                    {
                        String name = cubeFaces[i%6];
                        if (numSlices > 6)
                            name = string.Format("[{0}] {1}", (i / 6), cubeFaces[i%6]); // Front 1, Back 2, 3, 4 etc for cube arrays
                        sliceFace.Items.Add(name);
                    }
                    else
                    {
                        sliceFace.Items.Add("Slice " + i);
                    }
                }

                int firstArraySlice = -1;
                // only switch to the selected mip for outputs, and when changing drawcall
                if (!CurrentTextureIsLocked && m_Following.Type != FollowType.ReadOnly && newdraw)
                    firstArraySlice = m_Following.GetFirstArraySlice(m_Core);

                // see above with highestMip and prevHighestMip for the logic behind this
                if (firstArraySlice >= 0 && (newtex || firstArraySlice != prevFirstArraySlice))
                {
                    useslicesettings = false;
                    sliceFace.SelectedIndex = Helpers.Clamp(firstArraySlice, 0, (int)numSlices - 1);
                }

                if (sliceFace.SelectedIndex == -1)
                    sliceFace.SelectedIndex = Helpers.Clamp(prevFirstArraySlice, 0, (int)numSlices - 1);

                prevFirstArraySlice = firstArraySlice;
            }

            // because slice and mip are specially set above, we restore any per-tex settings to apply
            // even if we don't switch to a new texture.
            // Note that if the slice or mip was changed because that slice or mip is the selected one
            // at the API level, we leave this alone.
            if (m_Core.Config.TextureViewer_PerTexSettings && m_TextureSettings.ContainsKey(tex.ID))
            {
                if (usemipsettings)
                    mipLevel.SelectedIndex = m_TextureSettings[tex.ID].mip;

                if (useslicesettings)
                    sliceFace.SelectedIndex = m_TextureSettings[tex.ID].slice;
            }

            // handling for if we've switched to a new texture
            if (newtex)
            {
                // if we save certain settings per-texture, restore them (if we have any)
                if (m_Core.Config.TextureViewer_PerTexSettings && m_TextureSettings.ContainsKey(tex.ID))
                {
                    channels.SelectedIndex = m_TextureSettings[tex.ID].displayType;

                    customShader.Text = m_TextureSettings[tex.ID].customShader;

                    customRed.Checked = m_TextureSettings[tex.ID].r;
                    customGreen.Checked = m_TextureSettings[tex.ID].g;
                    customBlue.Checked = m_TextureSettings[tex.ID].b;
                    customAlpha.Checked = m_TextureSettings[tex.ID].a;

                    depthDisplay.Checked = m_TextureSettings[m_TexDisplay.texid].depth;
                    stencilDisplay.Checked = m_TextureSettings[m_TexDisplay.texid].stencil;

                    norangePaint = true;
                    rangeHistogram.SetRange(m_TextureSettings[m_TexDisplay.texid].minrange, m_TextureSettings[m_TexDisplay.texid].maxrange);
                    norangePaint = false;
                }
                else if (m_Core.Config.TextureViewer_PerTexSettings)
                {
                    // if we are using per-tex settings, reset back to RGB
                    channels.SelectedIndex = 0;

                    customShader.Text = "";

                    customRed.Checked = true;
                    customGreen.Checked = true;
                    customBlue.Checked = true;
                    customAlpha.Checked = false;

                    stencilDisplay.Checked = false;
                    depthDisplay.Checked = true;

                    norangePaint = true;
                    UI_SetHistogramRange(tex, m_TexDisplay.typeHint);
                    norangePaint = false;
                }

                // reset the range if desired
                if (m_Core.Config.TextureViewer_ResetRange)
                {
                    UI_SetHistogramRange(tex, m_TexDisplay.typeHint);
                }
            }

            UI_UpdateFittedScale();

            UI_UpdateTextureDetails();

            UI_UpdateChannels();

            if (autoFit.Checked)
                AutoFitRange();

            m_Core.Renderer.BeginInvoke((ReplayRenderer r) =>
            {
                RT_UpdateVisualRange(r);

                RT_UpdateAndDisplay(r);

                if (tex.ID != ResourceId.Null)
                {
                    if (m_Output != null)
                        RT_PickPixelsAndUpdate(m_PickedPoint.X, m_PickedPoint.Y, true);

                    var us = r.GetUsage(tex.ID);

                    var tb = m_Core.TimelineBar;

                    if (tb != null && tb.Visible && !tb.IsDisposed)
                    {
                        this.BeginInvoke(new Action(() =>
                        {
                            tb.HighlightResource(tex.ID, tex.name, us);
                        }));
                    }
                }
                else
                {
                    m_CurPixelValue = null;
                    m_CurRealValue = null;
                }
            });
        }