Exemple #1
0
        protected internal virtual void OnPaint(TimelineViewTrackPaintEventArgs e)
        {
            Rectangle rect = e.TargetRect;

            // Draw curve
            switch (e.GetAdjustedQuality(this.parentTrack.CurveQuality))
            {
            case QualityLevel.High:
                e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                break;

            default:
            case QualityLevel.Medium:
            case QualityLevel.Low:
                e.Graphics.SmoothingMode = SmoothingMode.HighSpeed;
                break;
            }
            float pixelWidth = this.ParentView.ConvertUnitsToPixels(this.model.EndTime - this.model.BeginTime);

            if (pixelWidth < 5)
            {
                e.Graphics.SmoothingMode = SmoothingMode.HighSpeed;
            }
            if (pixelWidth > 2)
            {
                this.OnPaintCurve(e);
            }
            e.Graphics.SmoothingMode = SmoothingMode.Default;

            // Draw overlay
            this.OnPaintBoundaries(e);
        }
        protected virtual void OnPaintCurve(TimelineViewTrackPaintEventArgs e)
        {
            // Ignore e.BeginTime and e.EndTime for sampling, as we're heavily dependent on rounding errors, etc. while undersampling. Instead, always sample the whole curve.
            float beginUnitX = Math.Max(this.ParentView.UnitOriginOffset - this.ParentView.UnitScroll, this.model.BeginTime);
            float endUnitX = Math.Min(this.ParentView.UnitOriginOffset - this.ParentView.UnitScroll + this.ParentView.VisibleUnitWidth, this.model.EndTime);

            // Determine graph parameters
            float minPixelStep;
            switch (e.GetAdjustedQuality(this.parentTrack.CurvePrecision))
            {
                case QualityLevel.High:
                    minPixelStep = 0.25f;
                    break;
                default:
                case QualityLevel.Medium:
                    minPixelStep = 0.5f;
                    break;
                case QualityLevel.Low:
                    minPixelStep = 1.0f;
                    break;
            }
            float visibleMax = this.model.GetMaxValueInRange(beginUnitX, endUnitX);
            float visibleMin = this.model.GetMinValueInRange(beginUnitX, endUnitX);
            float visiblePixelHeight = this.ParentTrack.ConvertUnitsToPixels(Math.Abs(visibleMax - visibleMin));
            if (visiblePixelHeight < 10.0f)			minPixelStep *= 8.0f;
            else if (visiblePixelHeight < 20.0f)	minPixelStep *= 4.0f;
            else if (visiblePixelHeight < 40.0f)	minPixelStep *= 2.0f;
            else if (visiblePixelHeight < 70.0f)	minPixelStep *= 1.5f;
            minPixelStep = Math.Min(minPixelStep, 4);
            float minUnitStep = this.ParentView.ConvertPixelsToUnits(minPixelStep);
            Rectangle rect = e.TargetRect;

            if (this.curveCacheDirty)
            {
                // Begin a little sooner, so interpolation / error checking can gather some data
                beginUnitX -= minUnitStep * 5.0f;

                // Determine sample points
                PointF[] curvePointsEnvMax = null;
                PointF[] curvePointsEnvMin = null;
                if (this.curveOpacity > 0.0f)
                {
                    this.cacheCurveVertices = this.GetCurvePoints(rect, e.GetAdjustedQuality(this.parentTrack.CurvePrecision), this.model.GetValueAtX, minPixelStep, beginUnitX, endUnitX);
                }
                if (this.envelopeOpacity > 0.0f && !this.skipEnvelope)
                {
                    float envelopeUnitRadius = this.ParentView.ConvertPixelsToUnits(EnvelopeBasePixelRadius);
                    float minEnvelopeStepFactor;
                    switch (e.GetAdjustedQuality(this.parentTrack.EnvelopePrecision))
                    {
                        case QualityLevel.High:
                            minEnvelopeStepFactor = 0.1f;
                            break;
                        default:
                        case QualityLevel.Medium:
                            minEnvelopeStepFactor = 0.5f;
                            break;
                        case QualityLevel.Low:
                            minEnvelopeStepFactor = 1.0f;
                            break;
                    }
                    float envelopePixelStep = minEnvelopeStepFactor * EnvelopeBasePixelRadius;
                    float envelopeUnitStep = minEnvelopeStepFactor * envelopeUnitRadius;
                    curvePointsEnvMax = this.GetCurvePoints(
                        rect,
             						e.GetAdjustedQuality(this.parentTrack.CurvePrecision),
                        x => this.model.GetMaxValueInRange(x - envelopeUnitRadius, x + envelopeUnitRadius),
                        envelopePixelStep,
                        envelopeUnitStep * (int)(beginUnitX / envelopeUnitStep),
                        envelopeUnitStep * ((int)(endUnitX / envelopeUnitStep) + 1));
                    curvePointsEnvMin = this.GetCurvePoints(
                        rect,
             						e.GetAdjustedQuality(this.parentTrack.CurvePrecision),
                        x => this.model.GetMinValueInRange(x - envelopeUnitRadius, x + envelopeUnitRadius),
                        envelopePixelStep,
                        envelopeUnitStep * (int)(beginUnitX / envelopeUnitStep),
                        envelopeUnitStep * ((int)(endUnitX / envelopeUnitStep) + 1));

                    if (curvePointsEnvMax == null || curvePointsEnvMin == null || curvePointsEnvMax.Length + curvePointsEnvMin.Length < 3)
                        this.skipEnvelope = true;
                }

                if (curvePointsEnvMax != null && curvePointsEnvMin != null && curvePointsEnvMax.Length + curvePointsEnvMin.Length >= 3)
                {
                    // Calculate the visible envelope polygon
                    this.cacheEnvelopeVertices = new PointF[curvePointsEnvMax.Length + curvePointsEnvMin.Length];
                    for (int i = 0; i < curvePointsEnvMax.Length; i++)
                    {
                        this.cacheEnvelopeVertices[i] = curvePointsEnvMax[i];
                    }
                    for (int i = 0; i < curvePointsEnvMin.Length; i++)
                    {
                        this.cacheEnvelopeVertices[curvePointsEnvMax.Length + i] = curvePointsEnvMin[curvePointsEnvMin.Length - i - 1];
                    }

                    // Calculate the envelope and curve gradients
                    if (this.cacheCurveVertices != null)
                    {
                        float varianceUnitRadius = this.ParentView.ConvertPixelsToUnits(0.5f);
                        KeyValuePair<float,float>[] baseBlend = new KeyValuePair<float,float>[Math.Max(this.cacheCurveVertices.Length, 2)];
                        for (int i = 0; i < baseBlend.Length; i++)
                        {
                            float relativeX = (float)(this.cacheCurveVertices[(int)((float)i * (this.cacheCurveVertices.Length - 1) / (float)(baseBlend.Length - 1))].X - rect.X) / (float)rect.Width;
                            float unitX = this.ParentView.GetUnitAtPos(rect.X + relativeX * rect.Width);
                            float localOpacity = this.GetEnvelopeVisibility(
                                this.model.GetMaxValueInRange(unitX - varianceUnitRadius, unitX + varianceUnitRadius) -
                                this.model.GetMinValueInRange(unitX - varianceUnitRadius, unitX + varianceUnitRadius));
                            baseBlend[i] = new KeyValuePair<float,float>(relativeX, localOpacity);
                        }

                        this.cacheEnvelopeGradient = new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, LinearGradientMode.Horizontal);
                        this.cacheCurveGradient = new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, LinearGradientMode.Horizontal);

                        const int Samples = 21;
                        const int SamplesHalf = Samples / 2;
                        const int BlendSamplesPerChunk = 4;
                        float highestOpacity = 0.0f;
                        ColorBlend envelopeBlend = new ColorBlend(Math.Max(baseBlend.Length * BlendSamplesPerChunk / Samples, 2));
                        ColorBlend curveBlend = new ColorBlend(Math.Max(baseBlend.Length * BlendSamplesPerChunk / Samples, 2));
                        for (int i = 0; i < envelopeBlend.Colors.Length; i++)
                        {
                            int firstIndex = Math.Min(Math.Max(i * Samples / BlendSamplesPerChunk - SamplesHalf, 0), baseBlend.Length - 1);
                            int lastIndex = Math.Min(Math.Max(i * Samples / BlendSamplesPerChunk + SamplesHalf, 0), baseBlend.Length - 1);
                            float sum = 0.0f;
                            for (int j = firstIndex; j <= lastIndex; j++)
                            {
                                sum += baseBlend[j].Value;
                            }
                            float localOpacity = sum / (float)(1 + lastIndex - firstIndex);
                            highestOpacity = Math.Max(highestOpacity, localOpacity);
                            envelopeBlend.Colors[i] = Color.FromArgb((int)(localOpacity * this.envelopeOpacity * 255.0f), this.baseColor);
                            envelopeBlend.Positions[i] = baseBlend[firstIndex + (lastIndex - firstIndex) / 2].Key;
                            curveBlend.Colors[i] = Color.FromArgb((int)((1.0f - localOpacity) * (1.0f - localOpacity) * this.curveOpacity * 255.0f), this.baseColor);
                            curveBlend.Positions[i] = baseBlend[firstIndex + (lastIndex - firstIndex) / 2].Key;
                        }

                        if (highestOpacity <= 0.05f)
                        {
                            this.cacheEnvelopeGradient = null;
                            this.cacheCurveGradient = null;
                            this.skipEnvelope = true;
                        }
                        else
                        {
                            envelopeBlend.Positions[0] = 0.0f;
                            envelopeBlend.Positions[envelopeBlend.Positions.Length - 1] = 1.0f;
                            this.cacheEnvelopeGradient.InterpolationColors = envelopeBlend;
                            curveBlend.Positions[0] = 0.0f;
                            curveBlend.Positions[curveBlend.Positions.Length - 1] = 1.0f;
                            this.cacheCurveGradient.InterpolationColors = curveBlend;
                        }
                    }
                }
            }

            // Draw the envelope area
            if (this.cacheEnvelopeGradient != null && this.cacheEnvelopeVertices != null && this.cacheEnvelopeVertices.Length >= 3)
            {
                e.Graphics.FillPolygon(this.cacheEnvelopeGradient, this.cacheEnvelopeVertices);
            }

            // Draw the graph
            if (this.cacheCurveVertices != null && this.cacheCurveVertices.Length >= 2)
            {
                Pen linePen;
                if (this.cacheCurveGradient != null)
                {
                    linePen = new Pen(this.cacheCurveGradient);
                }
                else
                {
                    linePen = new Pen(Color.FromArgb((int)(this.curveOpacity * 255.0f), this.baseColor));
                }
                e.Graphics.DrawLines(linePen, this.cacheCurveVertices);
            }

            // Keep in mind that our cache is no valid again
            if (e.GetAdjustedQuality(this.parentTrack.CurvePrecision) == this.parentTrack.CurvePrecision &&
                e.GetAdjustedQuality(this.parentTrack.EnvelopePrecision) == this.parentTrack.EnvelopePrecision)
            {
                this.curveCacheDirty = false;
            }
        }
        protected internal virtual void OnPaint(TimelineViewTrackPaintEventArgs e)
        {
            Rectangle rect = e.TargetRect;

            // Draw curve
            switch (e.GetAdjustedQuality(this.parentTrack.CurveQuality))
            {
                case QualityLevel.High:
                    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                    break;
                default:
                case QualityLevel.Medium:
                case QualityLevel.Low:
                    e.Graphics.SmoothingMode = SmoothingMode.HighSpeed;
                    break;
            }
            float pixelWidth = this.ParentView.ConvertUnitsToPixels(this.model.EndTime - this.model.BeginTime);
            if (pixelWidth < 5) e.Graphics.SmoothingMode = SmoothingMode.HighSpeed;
            if (pixelWidth > 2)
            {
                this.OnPaintCurve(e);
            }
            e.Graphics.SmoothingMode = SmoothingMode.Default;

            // Draw overlay
            this.OnPaintBoundaries(e);
        }
Exemple #4
0
        protected virtual void OnPaintCurve(TimelineViewTrackPaintEventArgs e)
        {
            // Ignore e.BeginTime and e.EndTime for sampling, as we're heavily dependent on rounding errors, etc. while undersampling. Instead, always sample the whole curve.
            float beginUnitX = Math.Max(this.ParentView.UnitOriginOffset - this.ParentView.UnitScroll, this.model.BeginTime);
            float endUnitX   = Math.Min(this.ParentView.UnitOriginOffset - this.ParentView.UnitScroll + this.ParentView.VisibleUnitWidth, this.model.EndTime);

            // Determine graph parameters
            float minPixelStep;

            switch (e.GetAdjustedQuality(this.parentTrack.CurvePrecision))
            {
            case QualityLevel.High:
                minPixelStep = 0.25f;
                break;

            default:
            case QualityLevel.Medium:
                minPixelStep = 0.5f;
                break;

            case QualityLevel.Low:
                minPixelStep = 1.0f;
                break;
            }
            float visibleMax         = this.model.GetMaxValueInRange(beginUnitX, endUnitX);
            float visibleMin         = this.model.GetMinValueInRange(beginUnitX, endUnitX);
            float visiblePixelHeight = this.ParentTrack.ConvertUnitsToPixels(Math.Abs(visibleMax - visibleMin));

            if (visiblePixelHeight < 10.0f)
            {
                minPixelStep *= 8.0f;
            }
            else if (visiblePixelHeight < 20.0f)
            {
                minPixelStep *= 4.0f;
            }
            else if (visiblePixelHeight < 40.0f)
            {
                minPixelStep *= 2.0f;
            }
            else if (visiblePixelHeight < 70.0f)
            {
                minPixelStep *= 1.5f;
            }
            minPixelStep = Math.Min(minPixelStep, 4);
            float     minUnitStep = this.ParentView.ConvertPixelsToUnits(minPixelStep);
            Rectangle rect        = e.TargetRect;


            if (this.curveCacheDirty)
            {
                // Begin a little sooner, so interpolation / error checking can gather some data
                beginUnitX -= minUnitStep * 5.0f;

                // Determine sample points
                PointF[] curvePointsEnvMax = null;
                PointF[] curvePointsEnvMin = null;
                if (this.curveOpacity > 0.0f)
                {
                    this.cacheCurveVertices = this.GetCurvePoints(rect, e.GetAdjustedQuality(this.parentTrack.CurvePrecision), this.model.GetValueAtX, minPixelStep, beginUnitX, endUnitX);
                }
                if (this.envelopeOpacity > 0.0f && !this.skipEnvelope)
                {
                    float envelopeUnitRadius = this.ParentView.ConvertPixelsToUnits(EnvelopeBasePixelRadius);
                    float minEnvelopeStepFactor;
                    switch (e.GetAdjustedQuality(this.parentTrack.EnvelopePrecision))
                    {
                    case QualityLevel.High:
                        minEnvelopeStepFactor = 0.1f;
                        break;

                    default:
                    case QualityLevel.Medium:
                        minEnvelopeStepFactor = 0.5f;
                        break;

                    case QualityLevel.Low:
                        minEnvelopeStepFactor = 1.0f;
                        break;
                    }
                    float envelopePixelStep = minEnvelopeStepFactor * EnvelopeBasePixelRadius;
                    float envelopeUnitStep  = minEnvelopeStepFactor * envelopeUnitRadius;
                    curvePointsEnvMax = this.GetCurvePoints(
                        rect,
                        e.GetAdjustedQuality(this.parentTrack.CurvePrecision),
                        x => this.model.GetMaxValueInRange(x - envelopeUnitRadius, x + envelopeUnitRadius),
                        envelopePixelStep,
                        envelopeUnitStep * (int)(beginUnitX / envelopeUnitStep),
                        envelopeUnitStep * ((int)(endUnitX / envelopeUnitStep) + 1));
                    curvePointsEnvMin = this.GetCurvePoints(
                        rect,
                        e.GetAdjustedQuality(this.parentTrack.CurvePrecision),
                        x => this.model.GetMinValueInRange(x - envelopeUnitRadius, x + envelopeUnitRadius),
                        envelopePixelStep,
                        envelopeUnitStep * (int)(beginUnitX / envelopeUnitStep),
                        envelopeUnitStep * ((int)(endUnitX / envelopeUnitStep) + 1));

                    if (curvePointsEnvMax == null || curvePointsEnvMin == null || curvePointsEnvMax.Length + curvePointsEnvMin.Length < 3)
                    {
                        this.skipEnvelope = true;
                    }
                }

                if (curvePointsEnvMax != null && curvePointsEnvMin != null && curvePointsEnvMax.Length + curvePointsEnvMin.Length >= 3)
                {
                    // Calculate the visible envelope polygon
                    this.cacheEnvelopeVertices = new PointF[curvePointsEnvMax.Length + curvePointsEnvMin.Length];
                    for (int i = 0; i < curvePointsEnvMax.Length; i++)
                    {
                        this.cacheEnvelopeVertices[i] = curvePointsEnvMax[i];
                    }
                    for (int i = 0; i < curvePointsEnvMin.Length; i++)
                    {
                        this.cacheEnvelopeVertices[curvePointsEnvMax.Length + i] = curvePointsEnvMin[curvePointsEnvMin.Length - i - 1];
                    }

                    // Calculate the envelope and curve gradients
                    if (this.cacheCurveVertices != null)
                    {
                        float varianceUnitRadius = this.ParentView.ConvertPixelsToUnits(0.5f);
                        KeyValuePair <float, float>[] baseBlend = new KeyValuePair <float, float> [Math.Max(this.cacheCurveVertices.Length, 2)];
                        for (int i = 0; i < baseBlend.Length; i++)
                        {
                            float relativeX    = (float)(this.cacheCurveVertices[(int)((float)i * (this.cacheCurveVertices.Length - 1) / (float)(baseBlend.Length - 1))].X - rect.X) / (float)rect.Width;
                            float unitX        = this.ParentView.GetUnitAtPos(rect.X + relativeX * rect.Width);
                            float localOpacity = this.GetEnvelopeVisibility(
                                this.model.GetMaxValueInRange(unitX - varianceUnitRadius, unitX + varianceUnitRadius) -
                                this.model.GetMinValueInRange(unitX - varianceUnitRadius, unitX + varianceUnitRadius));
                            baseBlend[i] = new KeyValuePair <float, float>(relativeX, localOpacity);
                        }

                        this.cacheEnvelopeGradient = new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, LinearGradientMode.Horizontal);
                        this.cacheCurveGradient    = new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, LinearGradientMode.Horizontal);

                        const int  Samples              = 21;
                        const int  SamplesHalf          = Samples / 2;
                        const int  BlendSamplesPerChunk = 4;
                        float      highestOpacity       = 0.0f;
                        ColorBlend envelopeBlend        = new ColorBlend(Math.Max(baseBlend.Length * BlendSamplesPerChunk / Samples, 2));
                        ColorBlend curveBlend           = new ColorBlend(Math.Max(baseBlend.Length * BlendSamplesPerChunk / Samples, 2));
                        for (int i = 0; i < envelopeBlend.Colors.Length; i++)
                        {
                            int   firstIndex = Math.Min(Math.Max(i * Samples / BlendSamplesPerChunk - SamplesHalf, 0), baseBlend.Length - 1);
                            int   lastIndex  = Math.Min(Math.Max(i * Samples / BlendSamplesPerChunk + SamplesHalf, 0), baseBlend.Length - 1);
                            float sum        = 0.0f;
                            for (int j = firstIndex; j <= lastIndex; j++)
                            {
                                sum += baseBlend[j].Value;
                            }
                            float localOpacity = sum / (float)(1 + lastIndex - firstIndex);
                            highestOpacity             = Math.Max(highestOpacity, localOpacity);
                            envelopeBlend.Colors[i]    = Color.FromArgb((int)(localOpacity * this.envelopeOpacity * 255.0f), this.baseColor);
                            envelopeBlend.Positions[i] = baseBlend[firstIndex + (lastIndex - firstIndex) / 2].Key;
                            curveBlend.Colors[i]       = Color.FromArgb((int)((1.0f - localOpacity) * (1.0f - localOpacity) * this.curveOpacity * 255.0f), this.baseColor);
                            curveBlend.Positions[i]    = baseBlend[firstIndex + (lastIndex - firstIndex) / 2].Key;
                        }

                        if (highestOpacity <= 0.05f)
                        {
                            this.cacheEnvelopeGradient = null;
                            this.cacheCurveGradient    = null;
                            this.skipEnvelope          = true;
                        }
                        else
                        {
                            envelopeBlend.Positions[0] = 0.0f;
                            envelopeBlend.Positions[envelopeBlend.Positions.Length - 1] = 1.0f;
                            this.cacheEnvelopeGradient.InterpolationColors = envelopeBlend;
                            curveBlend.Positions[0] = 0.0f;
                            curveBlend.Positions[curveBlend.Positions.Length - 1] = 1.0f;
                            this.cacheCurveGradient.InterpolationColors           = curveBlend;
                        }
                    }
                }
            }

            // Draw the envelope area
            if (this.cacheEnvelopeGradient != null && this.cacheEnvelopeVertices != null && this.cacheEnvelopeVertices.Length >= 3)
            {
                e.Graphics.FillPolygon(this.cacheEnvelopeGradient, this.cacheEnvelopeVertices);
            }

            // Draw the graph
            if (this.cacheCurveVertices != null && this.cacheCurveVertices.Length >= 2)
            {
                Pen linePen;
                if (this.cacheCurveGradient != null)
                {
                    linePen = new Pen(this.cacheCurveGradient);
                }
                else
                {
                    linePen = new Pen(Color.FromArgb((int)(this.curveOpacity * 255.0f), this.baseColor));
                }
                e.Graphics.DrawLines(linePen, this.cacheCurveVertices);
            }

            // Keep in mind that our cache is no valid again
            if (e.GetAdjustedQuality(this.parentTrack.CurvePrecision) == this.parentTrack.CurvePrecision &&
                e.GetAdjustedQuality(this.parentTrack.EnvelopePrecision) == this.parentTrack.EnvelopePrecision)
            {
                this.curveCacheDirty = false;
            }
        }