Ejemplo n.º 1
0
        private static void AddIntentsToElement(Element element, double[] allPointsTimeOrdered, Curve levelCurve, ColorGradient colorGradient, TimeSpan duration, EffectIntents elementData, bool allowZeroIntensity, Color? color = null)
        {
            if (element != null)
            {
                double lastPosition = allPointsTimeOrdered[0];
                TimeSpan lastEnd = TimeSpan.Zero;
                for (var i = 1; i < allPointsTimeOrdered.Length; i++)
                {
                    double position = allPointsTimeOrdered[i];
                    TimeSpan startTime = lastEnd;
                    TimeSpan timeSpan = TimeSpan.FromMilliseconds(duration.TotalMilliseconds * (position - lastPosition));

                    if (color == null)
                    {
                        var startColor = colorGradient.GetColorAt(lastPosition);
                        var endColor = colorGradient.GetColorAt(position);
                        var startIntensity = levelCurve.GetValue(lastPosition * 100) / 100;
                        var endIntensity = levelCurve.GetValue(position * 100) / 100;

                        if (allowZeroIntensity || !(startIntensity.Equals(0) && endIntensity.Equals(0)))
                        {
                            IIntent intent = IntentBuilder.CreateIntent(startColor, endColor, startIntensity, endIntensity, timeSpan);
                            elementData.AddIntentForElement(element.Id, intent, startTime);
                        }
                    }
                    else
                    {
                        var startIntensity = (colorGradient.GetProportionOfColorAt(lastPosition, (Color)color) * levelCurve.GetValue(lastPosition * 100) / 100);
                        var endIntensity = (colorGradient.GetProportionOfColorAt(position, (Color)color) * levelCurve.GetValue(position * 100) / 100);

                        if (allowZeroIntensity || !(startIntensity.Equals(0) && endIntensity.Equals(0)))
                        {
                            IIntent intent = IntentBuilder.CreateDiscreteIntent((Color)color, startIntensity, endIntensity, timeSpan);
                            elementData.AddIntentForElement(element.Id, intent, startTime);
                        }

                    }

                    lastPosition = position;
                    lastEnd = startTime + timeSpan;
                }
            }
        }
Ejemplo n.º 2
0
        private void GeneratePulse(ElementNode target, TimeSpan startTime, TimeSpan duration, double currentMovementPosition)
        {
            EffectIntents result = null;

            Pulse.Pulse pulse = new Pulse.Pulse();
            pulse.TargetNodes = new[] { target };
            pulse.TimeSpan    = duration;
            pulse.LevelCurve  = new Curve(PulseCurve);

            bool        discreteColors = ColorModule.isElementNodeDiscreteColored(target);
            IIntentNode intent;

            // figure out what color gradient to use for the pulse
            switch (ColorHandling)
            {
            case ChaseColorHandling.GradientForEachPulse:
                pulse.ColorGradient = ColorGradient;
                result = pulse.Render();
                result.OffsetAllCommandsByTime(startTime);
                if (ExtendPulseToStart && result.Count > 0)
                {
                    foreach (var iintentNode in result.FirstOrDefault().Value)
                    {
                        GenerateStartingStaticPulse(target, iintentNode);
                    }
                }
                _elementData.Add(result);
                if (ExtendPulseToEnd && result.Count > 0)
                {
                    foreach (var iintentNode in result.FirstOrDefault().Value)
                    {
                        GenerateExtendedStaticPulse(target, iintentNode);
                    }
                }
                break;

            case ChaseColorHandling.GradientThroughWholeEffect:
                double startPos = (startTime.Ticks / (double)TimeSpan.Ticks);
                double endPos   = ((startTime + duration).Ticks / (double)TimeSpan.Ticks);
                if (startPos < 0.0)
                {
                    startPos = 0.0;
                }
                if (endPos > 1.0)
                {
                    endPos = 1.0;
                }

                if (discreteColors)
                {
                    double range = endPos - startPos;
                    if (range <= 0.0)
                    {
                        Logging.Error("Chase: bad range: " + range + " (SP=" + startPos + ", EP=" + endPos + ")");
                        break;
                    }

                    ColorGradient cg = ColorGradient.GetSubGradientWithDiscreteColors(startPos, endPos);

                    foreach (Color color in cg.GetColorsInGradient())
                    {
                        Curve newCurve = new Curve(PulseCurve.Points);
                        foreach (PointPair point in newCurve.Points)
                        {
                            double effectRelativePosition = startPos + ((point.X / 100.0) * range);
                            double proportion             = ColorGradient.GetProportionOfColorAt(effectRelativePosition, color);
                            point.Y *= proportion;
                        }
                        pulse.LevelCurve    = newCurve;
                        pulse.ColorGradient = new ColorGradient(color);
                        result = pulse.Render();
                        result.OffsetAllCommandsByTime(startTime);
                        if (ExtendPulseToStart && result.Count > 0)
                        {
                            intent = result.FirstOrDefault().Value.FirstOrDefault();
                            GenerateStartingStaticPulse(target, intent);
                        }
                        _elementData.Add(result);
                        if (ExtendPulseToEnd && result.Count > 0)
                        {
                            intent = result.FirstOrDefault().Value.LastOrDefault();
                            GenerateExtendedStaticPulse(target, intent);
                        }
                    }
                }
                else
                {
                    pulse.ColorGradient = ColorGradient.GetSubGradient(startPos, endPos);
                    result = pulse.Render();
                    result.OffsetAllCommandsByTime(startTime);
                    if (ExtendPulseToStart && result.Count > 0)
                    {
                        intent = result.FirstOrDefault().Value.FirstOrDefault();
                        GenerateStartingStaticPulse(target, intent, ColorGradient.GetSubGradient(0, startPos));
                    }
                    _elementData.Add(result);
                    if (ExtendPulseToEnd && result.Count > 0)
                    {
                        intent = result.FirstOrDefault().Value.LastOrDefault();
                        GenerateExtendedStaticPulse(target, intent, ColorGradient.GetSubGradient(endPos, 1));
                    }
                }

                break;

            case ChaseColorHandling.StaticColor:
                pulse.ColorGradient = StaticColorGradient;
                result = pulse.Render();
                result.OffsetAllCommandsByTime(startTime);
                if (ExtendPulseToStart && result.Count > 0)
                {
                    intent = result.FirstOrDefault().Value.FirstOrDefault();
                    GenerateStartingStaticPulse(target, intent);
                }
                _elementData.Add(result);
                if (ExtendPulseToEnd && result.Count > 0)
                {
                    intent = result.FirstOrDefault().Value.LastOrDefault();
                    GenerateExtendedStaticPulse(target, intent);
                }
                break;

            case ChaseColorHandling.ColorAcrossItems:
                if (discreteColors)
                {
                    List <Tuple <Color, float> > colorsAtPosition = ColorGradient.GetDiscreteColorsAndProportionsAt(currentMovementPosition / 100.0);
                    foreach (Tuple <Color, float> colorProportion in colorsAtPosition)
                    {
                        float proportion = colorProportion.Item2;
                        // scale all levels of the pulse curve by the proportion that is applicable to this color
                        Curve newCurve = new Curve(PulseCurve.Points);
                        foreach (PointPair pointPair in newCurve.Points)
                        {
                            pointPair.Y *= proportion;
                        }
                        pulse.LevelCurve    = newCurve;
                        pulse.ColorGradient = new ColorGradient(colorProportion.Item1);
                        result = pulse.Render();
                        result.OffsetAllCommandsByTime(startTime);
                        if (ExtendPulseToStart && result.Count > 0)
                        {
                            intent = result.FirstOrDefault().Value.FirstOrDefault();
                            GenerateStartingStaticPulse(target, intent);
                        }
                        _elementData.Add(result);
                        if (ExtendPulseToEnd && result.Count > 0)
                        {
                            intent = result.FirstOrDefault().Value.LastOrDefault();
                            GenerateExtendedStaticPulse(target, intent);
                        }
                    }
                }
                else
                {
                    pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(currentMovementPosition / 100.0));
                    result = pulse.Render();
                    result.OffsetAllCommandsByTime(startTime);
                    if (ExtendPulseToStart && result.Count > 0)
                    {
                        intent = result.FirstOrDefault().Value.FirstOrDefault();
                        GenerateStartingStaticPulse(target, intent);
                    }
                    _elementData.Add(result);
                    if (ExtendPulseToEnd && result.Count > 0)
                    {
                        intent = result.FirstOrDefault().Value.LastOrDefault();
                        GenerateExtendedStaticPulse(target, intent);
                    }
                }
                break;
            }
        }
Ejemplo n.º 3
0
        private void DoRendering(CancellationTokenSource tokenSource = null)
        {
            //TODO: get a better increment time. doing it every X ms is..... shitty at best.
            TimeSpan increment = TimeSpan.FromMilliseconds(2);

            List <ElementNode> renderNodes = GetNodesToRenderOn();

            int targetNodeCount = renderNodes.Count;

            Pulse.Pulse   pulse;
            EffectIntents pulseData;

            // apply the 'background' values to all targets if the level is supposed to be nonzero
            if (DefaultLevel > 0)
            {
                int i = 0;
                foreach (ElementNode target in renderNodes)
                {
                    if (tokenSource != null && tokenSource.IsCancellationRequested)
                    {
                        return;
                    }

                    if (target != null && target.Element != null)
                    {
                        bool discreteColors = ColorModule.isElementNodeDiscreteColored(target);

                        pulse             = new Pulse.Pulse();
                        pulse.TargetNodes = new ElementNode[] { target };
                        pulse.TimeSpan    = TimeSpan;
                        double level = DefaultLevel * 100.0;

                        // figure out what color gradient to use for the pulse
                        switch (ColorHandling)
                        {
                        case ChaseColorHandling.GradientForEachPulse:
                            pulse.ColorGradient = StaticColorGradient;
                            pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { level, level }));
                            pulseData           = pulse.Render();
                            _elementData.Add(pulseData);
                            break;

                        case ChaseColorHandling.GradientThroughWholeEffect:
                            pulse.ColorGradient = ColorGradient;
                            pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { level, level }));
                            pulseData           = pulse.Render();
                            _elementData.Add(pulseData);
                            break;

                        case ChaseColorHandling.StaticColor:
                            pulse.ColorGradient = StaticColorGradient;
                            pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { level, level }));
                            pulseData           = pulse.Render();
                            _elementData.Add(pulseData);
                            break;

                        case ChaseColorHandling.ColorAcrossItems:
                            double positionWithinGroup = i / (double)targetNodeCount;
                            if (discreteColors)
                            {
                                List <Tuple <Color, float> > colorsAtPosition =
                                    ColorGradient.GetDiscreteColorsAndProportionsAt(positionWithinGroup);
                                foreach (Tuple <Color, float> colorProportion in colorsAtPosition)
                                {
                                    if (tokenSource != null && tokenSource.IsCancellationRequested)
                                    {
                                        return;
                                    }
                                    double value = level * colorProportion.Item2;
                                    pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { value, value }));
                                    pulse.ColorGradient = new ColorGradient(colorProportion.Item1);
                                    pulseData           = pulse.Render();
                                    _elementData.Add(pulseData);
                                }
                            }
                            else
                            {
                                pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup));
                                pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { level, level }));
                                pulseData           = pulse.Render();
                                _elementData.Add(pulseData);
                            }
                            break;
                        }

                        i++;
                    }
                }
            }


            // the total chase time
            TimeSpan chaseTime = TimeSpan.FromMilliseconds(TimeSpan.TotalMilliseconds - PulseOverlap);

            if (chaseTime.TotalMilliseconds <= 0)
            {
                chaseTime = TimeSpan.FromMilliseconds(1);
            }

            // we need to keep track of the element that is 'under' the curve at a given time, to see if it changes,
            // and when it does, we make the effect for it then (since it's a variable time pulse).
            ElementNode lastTargetedNode  = null;
            TimeSpan    lastNodeStartTime = TimeSpan.Zero;

            // iterate up to and including the last pulse generated
            for (TimeSpan current = TimeSpan.Zero; current <= TimeSpan; current += increment)
            {
                if (tokenSource != null && tokenSource.IsCancellationRequested)
                {
                    return;
                }
                double currentPercentageIntoChase = ((double)current.Ticks / (double)chaseTime.Ticks) * 100.0;

                double currentMovementPosition = ChaseMovement.GetValue(currentPercentageIntoChase);
                int    currentNodeIndex        = (int)((currentMovementPosition / 100.0) * targetNodeCount);

                // on the off chance we hit the 100% mark *exactly*...
                if (currentNodeIndex == targetNodeCount && currentNodeIndex > 0)
                {
                    currentNodeIndex--;
                }

                if (currentNodeIndex >= targetNodeCount)
                {
                    Logging.Warn(
                        "Chase effect: rendering, but the current node index is higher or equal to the total target nodes.");
                    continue;
                }

                if (currentNodeIndex < 0)
                {
                    continue;
                }

                ElementNode currentNode = renderNodes[currentNodeIndex];
                if (currentNode == lastTargetedNode)
                {
                    continue;
                }

                // if the last node targeted wasn't null, we need to make a pulse for it
                if (lastTargetedNode != null)
                {
                    TimeSpan duration = current - lastNodeStartTime + TimeSpan.FromMilliseconds(PulseOverlap);
                    GeneratePulse(lastTargetedNode, lastNodeStartTime, duration
                                  , currentMovementPosition);
                }

                lastTargetedNode  = currentNode;
                lastNodeStartTime = current;

                // if we've hit the 100% mark of the chase curve, bail (the last one gets generated after)
                if (currentPercentageIntoChase >= 100.0)
                {
                    break;
                }
            }

            // generate the last pulse
            if (lastTargetedNode != null)
            {
                GeneratePulse(lastTargetedNode, lastNodeStartTime, TimeSpan - lastNodeStartTime, 1.0);
            }

            _elementData = EffectIntents.Restrict(_elementData, TimeSpan.Zero, TimeSpan);
        }
Ejemplo n.º 4
0
        private EffectIntents RenderElement(ElementNode node, double positionWithinGroup,
                                            List <IndividualTwinkleDetails> twinkles = null)
        {
            if (node == null || node.Element == null)
            {
                return(null);
            }

            if (twinkles == null)
            {
                twinkles = GenerateTwinkleData();
            }

            EffectIntents result = new EffectIntents();

            bool discreteColors = ColorModule.isElementNodeDiscreteColored(node);

            // render the flat 'minimum value' across the entire effect
            Pulse.Pulse pulse = new Pulse.Pulse();
            pulse.TargetNodes = new ElementNode[] { node };
            pulse.TimeSpan    = TimeSpan;
            double        minPulseValue = MinimumLevel * 100.0;
            EffectIntents pulseData;

            // figure out what color gradient to use for the pulse
            if (MinimumLevel > 0.0)
            {
                switch (ColorHandling)
                {
                case TwinkleColorHandling.GradientForEachPulse:
                    if (discreteColors)
                    {
                        List <Tuple <Color, float> > colorProportions = ColorGradient.GetDiscreteColorsAndProportionsAt(0);
                        foreach (Tuple <Color, float> colorProportion in colorProportions)
                        {
                            double value = minPulseValue * colorProportion.Item2;
                            pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { value, value }));
                            pulse.ColorGradient = new ColorGradient(colorProportion.Item1);
                            pulseData           = pulse.Render();
                            result.Add(pulseData);
                        }
                    }
                    else
                    {
                        pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { minPulseValue, minPulseValue }));
                        pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(0));
                        pulseData           = pulse.Render();
                        result.Add(pulseData);
                    }
                    break;

                case TwinkleColorHandling.GradientThroughWholeEffect:
                    pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { minPulseValue, minPulseValue }));
                    pulse.ColorGradient = ColorGradient;
                    pulseData           = pulse.Render();
                    result.Add(pulseData);
                    break;

                case TwinkleColorHandling.StaticColor:
                    pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { minPulseValue, minPulseValue }));
                    pulse.ColorGradient = StaticColorGradient;
                    pulseData           = pulse.Render();
                    result.Add(pulseData);
                    break;

                case TwinkleColorHandling.ColorAcrossItems:
                    if (discreteColors)
                    {
                        List <Tuple <Color, float> > colorsAtPosition = ColorGradient.GetDiscreteColorsAndProportionsAt(positionWithinGroup);
                        foreach (Tuple <Color, float> colorProportion in colorsAtPosition)
                        {
                            double value = minPulseValue * colorProportion.Item2;
                            pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { value, value }));
                            pulse.ColorGradient = new ColorGradient(colorProportion.Item1);
                            pulseData           = pulse.Render();
                            result.Add(pulseData);
                        }
                    }
                    else
                    {
                        pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { minPulseValue, minPulseValue }));
                        pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup));
                        pulseData           = pulse.Render();
                        result.Add(pulseData);
                    }
                    break;
                }
            }

            // render all the individual twinkles
            foreach (IndividualTwinkleDetails twinkle in twinkles)
            {
                {
                    // make a pulse for it

                    pulse.TargetNodes = new [] { node };
                    pulse.TimeSpan    = twinkle.Duration;
                    pulse.LevelCurve  = new Curve(new PointPairList(new double[] { 0, 50, 100 }, new [] { twinkle.curvePoints[0], twinkle.curvePoints[1], twinkle.curvePoints[2] }));

                    // figure out what color gradient to use for the pulse
                    switch (ColorHandling)
                    {
                    case TwinkleColorHandling.GradientForEachPulse:
                        pulse.ColorGradient = ColorGradient;
                        pulseData           = pulse.Render();
                        pulseData.OffsetAllCommandsByTime(twinkle.StartTime);
                        result.Add(pulseData);
                        break;

                    case TwinkleColorHandling.GradientThroughWholeEffect:
                        double startPos = ((double)twinkle.StartTime.Ticks / (double)TimeSpan.Ticks);
                        double endPos   = ((double)(twinkle.StartTime + twinkle.Duration).Ticks / (double)TimeSpan.Ticks);

                        if (discreteColors)
                        {
                            double range = endPos - startPos;
                            if (range <= 0.0)
                            {
                                Logging.Error("Twinkle: bad range: " + range + " (SP=" + startPos + ", EP=" + endPos + ")");
                                break;
                            }

                            ColorGradient cg = ColorGradient.GetSubGradientWithDiscreteColors(startPos, endPos);

                            foreach (Color color in cg.GetColorsInGradient())
                            {
                                Curve newCurve = new Curve(pulse.LevelCurve.Points);
                                foreach (PointPair point in newCurve.Points)
                                {
                                    double effectRelativePosition = startPos + ((point.X / 100.0) * range);
                                    double proportion             = ColorGradient.GetProportionOfColorAt(effectRelativePosition, color);
                                    point.Y *= proportion;
                                }
                                pulse.LevelCurve    = newCurve;
                                pulse.ColorGradient = new ColorGradient(color);
                                pulseData           = pulse.Render();
                                pulseData.OffsetAllCommandsByTime(twinkle.StartTime);
                                result.Add(pulseData);
                            }
                        }
                        else
                        {
                            pulse.ColorGradient = ColorGradient.GetSubGradient(startPos, endPos);
                            pulseData           = pulse.Render();
                            pulseData.OffsetAllCommandsByTime(twinkle.StartTime);
                            result.Add(pulseData);
                        }
                        break;

                    case TwinkleColorHandling.StaticColor:
                        pulse.ColorGradient = StaticColorGradient;
                        pulseData           = pulse.Render();
                        pulseData.OffsetAllCommandsByTime(twinkle.StartTime);
                        result.Add(pulseData);
                        break;

                    case TwinkleColorHandling.ColorAcrossItems:
                        if (discreteColors)
                        {
                            List <Tuple <Color, float> > colorsAtPosition = ColorGradient.GetDiscreteColorsAndProportionsAt(positionWithinGroup);
                            foreach (Tuple <Color, float> colorProportion in colorsAtPosition)
                            {
                                float proportion = colorProportion.Item2;
                                // scale all levels of the twinkle curve by the proportion that is applicable to this color
                                Curve newCurve = new Curve(pulse.LevelCurve.Points);
                                foreach (PointPair pointPair in newCurve.Points)
                                {
                                    pointPair.Y *= proportion;
                                }
                                pulse.LevelCurve    = newCurve;
                                pulse.ColorGradient = new ColorGradient(colorProportion.Item1);
                                pulseData           = pulse.Render();
                                pulseData.OffsetAllCommandsByTime(twinkle.StartTime);
                                result.Add(pulseData);
                            }
                        }
                        else
                        {
                            pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup));
                            pulseData           = pulse.Render();
                            pulseData.OffsetAllCommandsByTime(twinkle.StartTime);
                            result.Add(pulseData);
                        }
                        break;
                    }
                }
            }

            return(result);
        }
Ejemplo n.º 5
0
        private EffectIntents RenderElement(ElementNode node, double positionWithinGroup, List <IndividualTwinkleDetails> twinkles = null)
        {
            if (node == null)
            {
                return(null);
            }

            if (twinkles == null)
            {
                twinkles = GenerateTwinkleData();
            }

            EffectIntents result = new EffectIntents();

            // render the flat 'minimum value' across the entire effect
            Pulse.Pulse pulse = new Pulse.Pulse();
            pulse.TargetNodes = new ElementNode[] { node };
            pulse.TimeSpan    = TimeSpan;
            pulse.LevelCurve  = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { MinimumLevel * 100.0, MinimumLevel * 100.0 }));

            // figure out what color gradient to use for the pulse
            switch (ColorHandling)
            {
            case TwinkleColorHandling.GradientForEachPulse:
                pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(0));
                break;

            case TwinkleColorHandling.GradientThroughWholeEffect:
                pulse.ColorGradient = ColorGradient;
                break;

            case TwinkleColorHandling.StaticColor:
                pulse.ColorGradient = new ColorGradient(StaticColor);
                break;

            case TwinkleColorHandling.ColorAcrossItems:
                pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup));
                break;
            }

            EffectIntents pulseData = pulse.Render();

            result.Add(pulseData);

            // render all the individual twinkles
            foreach (IndividualTwinkleDetails twinkle in twinkles)
            {
                {
                    // make a pulse for it
                    pulse             = new Pulse.Pulse();
                    pulse.TargetNodes = new ElementNode[] { node };
                    pulse.TimeSpan    = twinkle.Duration;
                    pulse.LevelCurve  = twinkle.TwinkleCurve;

                    // figure out what color gradient to use for the pulse
                    switch (ColorHandling)
                    {
                    case TwinkleColorHandling.GradientForEachPulse:
                        pulse.ColorGradient = ColorGradient;
                        break;

                    case TwinkleColorHandling.GradientThroughWholeEffect:
                        double startPos = ((double)twinkle.StartTime.Ticks / (double)TimeSpan.Ticks);
                        double endPos   = ((double)(twinkle.StartTime + twinkle.Duration).Ticks / (double)TimeSpan.Ticks);
                        pulse.ColorGradient = ColorGradient.GetSubGradient(startPos, endPos);
                        break;

                    case TwinkleColorHandling.StaticColor:
                        pulse.ColorGradient = new ColorGradient(StaticColor);
                        break;

                    case TwinkleColorHandling.ColorAcrossItems:
                        pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup));
                        break;
                    }

                    pulseData = pulse.Render();
                    pulseData.OffsetAllCommandsByTime(twinkle.StartTime);
                    result.Add(pulseData);
                }
            }

            return(result);
        }
Ejemplo n.º 6
0
        private void DoRendering()
        {
            //TODO: get a better increment time. doing it every X ms is..... shitty at best.
            TimeSpan increment = TimeSpan.FromMilliseconds(2);

            List <ElementNode> renderNodes = GetNodesToRenderOn();

            int targetNodeCount = renderNodes.Count;

            Pulse.Pulse   pulse;
            EffectIntents pulseData;

            // apply the 'background' values to all targets
            int i = 0;

            foreach (ElementNode target in renderNodes)
            {
                pulse             = new Pulse.Pulse();
                pulse.TargetNodes = new ElementNode[] { target };
                pulse.TimeSpan    = TimeSpan;
                pulse.LevelCurve  = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { DefaultLevel * 100, DefaultLevel * 100 }));

                // figure out what color gradient to use for the pulse
                switch (ColorHandling)
                {
                case ChaseColorHandling.GradientForEachPulse:
                    pulse.ColorGradient = new ColorGradient(StaticColor);
                    break;

                case ChaseColorHandling.GradientThroughWholeEffect:
                    pulse.ColorGradient = ColorGradient;
                    break;

                case ChaseColorHandling.StaticColor:
                    pulse.ColorGradient = new ColorGradient(StaticColor);
                    break;

                case ChaseColorHandling.ColorAcrossItems:
                    pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt((double)i / (double)targetNodeCount));
                    break;
                }

                pulseData = pulse.Render();
                _elementData.Add(pulseData);
                i++;
            }


            // the total chase time
            TimeSpan chaseTime = TimeSpan.FromMilliseconds(TimeSpan.TotalMilliseconds - PulseOverlap);

            if (chaseTime.TotalMilliseconds <= 0)
            {
                chaseTime = TimeSpan.FromMilliseconds(1);
            }

            // we need to keep track of the element that is 'under' the curve at a given time, to see if it changes,
            // and when it does, we make the effect for it then (since it's a variable time pulse).
            ElementNode lastTargetedNode  = null;
            TimeSpan    lastNodeStartTime = TimeSpan.Zero;

            // iterate up to and including the last pulse generated
            for (TimeSpan current = TimeSpan.Zero; current <= TimeSpan; current += increment)
            {
                double currentPercentageIntoChase = ((double)current.Ticks / (double)chaseTime.Ticks) * 100.0;

                double currentMovementPosition = ChaseMovement.GetValue(currentPercentageIntoChase);
                int    currentNodeIndex        = (int)((currentMovementPosition / 100.0) * targetNodeCount);

                // on the off chance we hit the 100% mark *exactly*...
                if (currentNodeIndex == targetNodeCount)
                {
                    currentNodeIndex--;
                }

                if (currentNodeIndex >= targetNodeCount)
                {
                    VixenSystem.Logging.Warning("Chase effect: rendering, but the current node index is higher or equal to the total target nodes.");
                    continue;
                }

                ElementNode currentNode = renderNodes[currentNodeIndex];
                if (currentNode == lastTargetedNode)
                {
                    continue;
                }

                // if the last node targeted wasn't null, we need to make a pulse for it
                if (lastTargetedNode != null)
                {
                    GeneratePulse(lastTargetedNode, lastNodeStartTime, current - lastNodeStartTime + TimeSpan.FromMilliseconds(PulseOverlap), currentMovementPosition);
                }

                lastTargetedNode  = currentNode;
                lastNodeStartTime = current;

                // if we've hit the 100% mark of the chase curve, bail (the last one gets generated after)
                if (currentPercentageIntoChase >= 100.0)
                {
                    break;
                }
            }

            // generate the last pulse
            if (lastTargetedNode != null)
            {
                GeneratePulse(lastTargetedNode, lastNodeStartTime, TimeSpan - lastNodeStartTime, 1.0);
            }

            _elementData = EffectIntents.Restrict(_elementData, TimeSpan.Zero, TimeSpan);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Convienience method to generate intents that knows how to deal with discrete colors.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="gradient"></param>
        /// <param name="level"></param>
        /// <param name="startPos"></param>
        /// <param name="endPos"></param>
        /// <param name="duration"></param>
        /// <param name="startTime"></param>
        /// <param name="isDiscrete"></param>
        /// <returns></returns>
        protected EffectIntents GenerateEffectIntents(ElementNode node, ColorGradient gradient, Curve level, double startPos, double endPos,
            TimeSpan duration, TimeSpan startTime, bool isDiscrete)
        {
            EffectIntents result = new EffectIntents();
            if (isDiscrete)
            {
                IEnumerable<Color> colors = ColorModule.getValidColorsForElementNode(node, false)
                         .Intersect(gradient.GetColorsInGradient());
                foreach (Color color in colors)
                {
                    double proportion = gradient.GetProportionOfColorAt(startPos, color);
                    var startIntensity = (level.GetValue(startPos * 100) / 100) * proportion;
                    proportion = gradient.GetProportionOfColorAt(endPos, color);
                    var endIntensity = (level.GetValue(endPos * 100) / 100) * proportion;
                    if (startIntensity > 0 && endIntensity > 0)
                    {
                        var intent = CreateDiscreteIntent(color, startIntensity, endIntensity, duration);
                        result.AddIntentForElement(node.Element.Id, intent, startTime);
                    }
                }
            }
            else
            {
                var startIntensity = level.GetValue(startPos * 100) / 100;
                var endIntensity = level.GetValue(endPos * 100) / 100;
                if (startIntensity > 0 && endIntensity > 0)
                {
                    var intent = CreateIntent(gradient.GetColorAt(startPos), gradient.GetColorAt(endPos), startIntensity, endIntensity, duration);
                    result.AddIntentForElement(node.Element.Id, intent, startTime);
                }
            }

            return result;
        }
Ejemplo n.º 8
0
Archivo: Spin.cs Proyecto: ctmal/vixen
        private void DoRendering()
        {
            //TODO: get a better increment time. doing it every X ms is..... shitty at best.
            TimeSpan increment = TimeSpan.FromMilliseconds(10);

            List <ElementNode> renderNodes = GetNodesToRenderOn();
            int         targetNodeCount    = renderNodes.Count;
            ElementNode lastTargetedNode   = null;

            Pulse.Pulse   pulse;
            EffectIntents pulseData;

            // apply the 'background' values to all targets
            int i = 0;

            foreach (ElementNode target in renderNodes)
            {
                if (target != null)
                {
                    pulse             = new Pulse.Pulse();
                    pulse.TargetNodes = new ElementNode[] { target };
                    pulse.TimeSpan    = TimeSpan;
                    pulse.LevelCurve  = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { DefaultLevel * 100.0, DefaultLevel * 100.0 }));

                    // figure out what color gradient to use for the pulse
                    switch (ColorHandling)
                    {
                    case SpinColorHandling.GradientForEachPulse:
                        pulse.ColorGradient = new ColorGradient(StaticColor);
                        break;

                    case SpinColorHandling.GradientThroughWholeEffect:
                        pulse.ColorGradient = ColorGradient;
                        break;

                    case SpinColorHandling.StaticColor:
                        pulse.ColorGradient = new ColorGradient(StaticColor);
                        break;

                    case SpinColorHandling.ColorAcrossItems:
                        pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt((double)i / (double)targetNodeCount));
                        break;
                    }

                    pulseData = pulse.Render();
                    _elementData.Add(pulseData);
                    i++;
                }
            }

            // calculate the pulse time and revolution time exactly (based on the parameters from the data)
            double revTimeMs = 0;                                       // single revolution time (ms)

            // figure out the relative length of a individual pulse
            double pulseConstant   = 0;                                 // how much of each pulse is a constant time
            double pulseFractional = 0;                                 // how much of each pulse is a fraction of a single spin

            if (PulseLengthFormat == SpinPulseLengthFormat.FixedTime)
            {
                pulseConstant = PulseTime;
            }
            else if (PulseLengthFormat == SpinPulseLengthFormat.PercentageOfRevolution)
            {
                pulseFractional = PulsePercentage / 100.0;
            }
            else if (PulseLengthFormat == SpinPulseLengthFormat.EvenlyDistributedAcrossSegments)
            {
                pulseFractional = 1.0 / (double)targetNodeCount;
            }

            // magic number. (the inaccuracy of interpolating the curve into a position. eg. if we have 5 'positions', then
            // the curve should really be from 0-80% for the last spin, to make sure the last pulse finishes accurately.)
            double pulseInterpolationOffset = 1.0 / (double)targetNodeCount;

            // figure out either the revolution count or time, based on what data we have
            if (SpeedFormat == SpinSpeedFormat.RevolutionCount)
            {
                revTimeMs = (TimeSpan.TotalMilliseconds - pulseConstant) / (RevolutionCount + pulseFractional - pulseInterpolationOffset);
            }
            else if (SpeedFormat == SpinSpeedFormat.RevolutionFrequency)
            {
                revTimeMs = (1.0 / RevolutionFrequency) * 1000.0;                       // convert Hz to period ms
            }
            else if (SpeedFormat == SpinSpeedFormat.FixedTime)
            {
                revTimeMs = RevolutionTime;
            }

            double pulTimeMs = pulseConstant + (revTimeMs * pulseFractional);

            TimeSpan revTimeSpan   = TimeSpan.FromMilliseconds(revTimeMs);
            TimeSpan pulseTimeSpan = TimeSpan.FromMilliseconds(pulTimeMs);

            // figure out which way we're moving through the elements
            Curve movement;

            if (ReverseSpin)
            {
                movement = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { 100, 0 }));
            }
            else
            {
                movement = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { 0, 100 }));
            }

            // iterate up to and including the last pulse generated
            // a bit iffy, but stops 'carry over' spins past the end (when there's overlapping spins). But we need to go past
            // (total - pulse) as the last pulse can often be a bit inaccurate due to the rounding of the increment
            for (TimeSpan current = TimeSpan.Zero; current <= TimeSpan - pulseTimeSpan + increment; current += increment)
            {
                double currentPercentageIntoSpin = ((double)(current.Ticks % revTimeSpan.Ticks) / (double)revTimeSpan.Ticks) * 100.0;

                double targetElementPosition = movement.GetValue(currentPercentageIntoSpin);
                int    currentNodeIndex      = (int)((targetElementPosition / 100.0) * targetNodeCount);

                // on the off chance we hit the 100% mark *exactly*...
                if (currentNodeIndex == targetNodeCount)
                {
                    currentNodeIndex--;
                }

                if (currentNodeIndex >= targetNodeCount)
                {
                    VixenSystem.Logging.Warning("Spin effect: rendering, but the current node index is higher or equal to the total target nodes.");
                    continue;
                }

                ElementNode currentNode = renderNodes[currentNodeIndex];
                if (currentNode == lastTargetedNode)
                {
                    continue;
                }

                // make a pulse for it
                pulse             = new Pulse.Pulse();
                pulse.TargetNodes = new ElementNode[] { currentNode };
                pulse.TimeSpan    = pulseTimeSpan;
                pulse.LevelCurve  = new Curve(PulseCurve);

                // figure out what color gradient to use for the pulse
                switch (ColorHandling)
                {
                case SpinColorHandling.GradientForEachPulse:
                    pulse.ColorGradient = ColorGradient;
                    break;

                case SpinColorHandling.GradientThroughWholeEffect:
                    double startPos = ((double)current.Ticks / (double)TimeSpan.Ticks);
                    double endPos   = 1.0;
                    if (TimeSpan - current >= pulseTimeSpan)
                    {
                        endPos = ((double)(current + pulseTimeSpan).Ticks / (double)TimeSpan.Ticks);
                    }
                    pulse.ColorGradient = ColorGradient.GetSubGradient(startPos, endPos);
                    break;

                case SpinColorHandling.StaticColor:
                    pulse.ColorGradient = new ColorGradient(StaticColor);
                    break;

                case SpinColorHandling.ColorAcrossItems:
                    pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(targetElementPosition / 100.0));
                    break;
                }

                pulseData = pulse.Render();
                pulseData.OffsetAllCommandsByTime(current);
                _elementData.Add(pulseData);

                lastTargetedNode = currentNode;
            }

            _elementData = EffectIntents.Restrict(_elementData, TimeSpan.Zero, TimeSpan);
        }
Ejemplo n.º 9
0
        private void DoRendering(CancellationTokenSource tokenSource = null)
        {
            //TODO: get a better increment time. doing it every X ms is..... shitty at best.
            TimeSpan increment = TimeSpan.FromMilliseconds(10);

            List <ElementNode> renderNodes = GetNodesToRenderOn();
            int targetNodeCount            = renderNodes.Count;

            //If there are no nodes to render on Exit!
            if (targetNodeCount == 0)
            {
                return;
            }

            ElementNode lastTargetedNode = null;

            Pulse.Pulse   pulse;
            EffectIntents pulseData;

            // apply the 'background' values to all targets if nonzero
            if (DefaultLevel > 0)
            {
                int i = 0;
                foreach (ElementNode target in renderNodes)
                {
                    if (tokenSource != null && tokenSource.IsCancellationRequested)
                    {
                        return;
                    }

                    bool discreteColors = ColorModule.isElementNodeDiscreteColored(target);

                    if (target == null)
                    {
                        continue;
                    }

                    if (target != null)
                    {
                        pulse             = new Pulse.Pulse();
                        pulse.TargetNodes = new ElementNode[] { target };
                        pulse.TimeSpan    = TimeSpan;
                        double level = DefaultLevel * 100.0;

                        // figure out what color gradient to use for the pulse
                        switch (ColorHandling)
                        {
                        case SpinColorHandling.GradientForEachPulse:
                            pulse.ColorGradient = StaticColorGradient;
                            pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { level, level }));
                            pulseData           = pulse.Render();
                            _elementData.Add(pulseData);
                            break;

                        case SpinColorHandling.GradientThroughWholeEffect:
                            pulse.ColorGradient = ColorGradient;
                            pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { level, level }));
                            pulseData           = pulse.Render();
                            _elementData.Add(pulseData);
                            break;

                        case SpinColorHandling.StaticColor:
                            pulse.ColorGradient = StaticColorGradient;
                            pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { level, level }));
                            pulseData           = pulse.Render();
                            _elementData.Add(pulseData);
                            break;

                        case SpinColorHandling.ColorAcrossItems:
                            double positionWithinGroup = i / (double)targetNodeCount;
                            if (discreteColors)
                            {
                                List <Tuple <Color, float> > colorsAtPosition =
                                    ColorGradient.GetDiscreteColorsAndProportionsAt(positionWithinGroup);
                                foreach (Tuple <Color, float> colorProportion in colorsAtPosition)
                                {
                                    double value = level * colorProportion.Item2;
                                    pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { value, value }));
                                    pulse.ColorGradient = new ColorGradient(colorProportion.Item1);
                                    pulseData           = pulse.Render();
                                    _elementData.Add(pulseData);
                                }
                            }
                            else
                            {
                                pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup));
                                pulse.LevelCurve    = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { level, level }));
                                pulseData           = pulse.Render();
                                _elementData.Add(pulseData);
                            }
                            break;
                        }

                        i++;
                    }
                }
            }

            // calculate the pulse time and revolution time exactly (based on the parameters from the data)
            double revTimeMs = 0;             // single revolution time (ms)

            // figure out the relative length of a individual pulse
            double pulseConstant   = 0;           // how much of each pulse is a constant time
            double pulseFractional = 0;           // how much of each pulse is a fraction of a single spin

            if (PulseLengthFormat == SpinPulseLengthFormat.FixedTime)
            {
                pulseConstant = PulseTime;
            }
            else if (PulseLengthFormat == SpinPulseLengthFormat.PercentageOfRevolution)
            {
                pulseFractional = PulsePercentage / 100.0;
            }
            else if (PulseLengthFormat == SpinPulseLengthFormat.EvenlyDistributedAcrossSegments)
            {
                pulseFractional = 1.0 / (double)targetNodeCount;
            }

            // magic number. (the inaccuracy of interpolating the curve into a position. eg. if we have 5 'positions', then
            // the curve should really be from 0-80% for the last spin, to make sure the last pulse finishes accurately.)
            double pulseInterpolationOffset = 1.0 / (double)targetNodeCount;

            // figure out either the revolution count or time, based on what data we have
            if (SpeedFormat == SpinSpeedFormat.RevolutionCount)
            {
                revTimeMs = (TimeSpan.TotalMilliseconds - pulseConstant) /
                            (RevolutionCount + pulseFractional - pulseInterpolationOffset);
            }
            else if (SpeedFormat == SpinSpeedFormat.RevolutionFrequency)
            {
                revTimeMs = (1.0 / RevolutionFrequency) * 1000.0;             // convert Hz to period ms
            }
            else if (SpeedFormat == SpinSpeedFormat.FixedTime)
            {
                revTimeMs = RevolutionTime;
            }

            double pulTimeMs = pulseConstant + (revTimeMs * pulseFractional);

            TimeSpan revTimeSpan   = TimeSpan.FromMilliseconds(revTimeMs);
            TimeSpan pulseTimeSpan = TimeSpan.FromMilliseconds(pulTimeMs);

            // figure out which way we're moving through the elements
            Curve movement;

            if (ReverseSpin)
            {
                movement = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { 100, 0 }));
            }
            else
            {
                movement = new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { 0, 100 }));
            }

            // iterate up to and including the last pulse generated
            // a bit iffy, but stops 'carry over' spins past the end (when there's overlapping spins). But we need to go past
            // (total - pulse) as the last pulse can often be a bit inaccurate due to the rounding of the increment
            for (TimeSpan current = TimeSpan.Zero; current <= TimeSpan - pulseTimeSpan + increment; current += increment)
            {
                if (tokenSource != null && tokenSource.IsCancellationRequested)
                {
                    return;
                }

                double currentPercentageIntoSpin = ((double)(current.Ticks % revTimeSpan.Ticks) / (double)revTimeSpan.Ticks) * 100.0;

                double targetElementPosition = movement.GetValue(currentPercentageIntoSpin);
                int    currentNodeIndex      = (int)((targetElementPosition / 100.0) * targetNodeCount);

                // on the off chance we hit the 100% mark *exactly*...
                if (currentNodeIndex == targetNodeCount)
                {
                    currentNodeIndex--;
                }

                if (currentNodeIndex >= targetNodeCount)
                {
                    Logging.Warn(
                        "Spin effect: rendering, but the current node index is higher or equal to the total target nodes.");
                    continue;
                }

                ElementNode currentNode = renderNodes[currentNodeIndex];
                if (currentNode == lastTargetedNode)
                {
                    continue;
                }

                bool discreteColors = ColorModule.isElementNodeDiscreteColored(currentNode);

                // make a pulse for it
                pulse             = new Pulse.Pulse();
                pulse.TargetNodes = new ElementNode[] { currentNode };
                pulse.TimeSpan    = pulseTimeSpan;
                pulse.LevelCurve  = new Curve(PulseCurve);

                // figure out what color gradient to use for the pulse
                switch (ColorHandling)
                {
                case SpinColorHandling.GradientForEachPulse:
                    pulse.ColorGradient = ColorGradient;
                    pulseData           = pulse.Render();
                    pulseData.OffsetAllCommandsByTime(current);
                    _elementData.Add(pulseData);
                    break;

                case SpinColorHandling.GradientThroughWholeEffect:
                    double startPos = ((double)current.Ticks / (double)TimeSpan.Ticks);
                    double endPos   = 1.0;
                    if (TimeSpan - current >= pulseTimeSpan)
                    {
                        endPos = ((double)(current + pulseTimeSpan).Ticks / (double)TimeSpan.Ticks);
                    }

                    if (discreteColors)
                    {
                        double range = endPos - startPos;
                        if (range <= 0.0)
                        {
                            Logging.Error("Spin: bad range: " + range + " (SP=" + startPos + ", EP=" + endPos + ")");
                            break;
                        }

                        ColorGradient cg = ColorGradient.GetSubGradientWithDiscreteColors(startPos, endPos);

                        foreach (Color color in cg.GetColorsInGradient())
                        {
                            if (tokenSource != null && tokenSource.IsCancellationRequested)
                            {
                                return;
                            }

                            Curve newCurve = new Curve(pulse.LevelCurve.Points);
                            foreach (PointPair point in newCurve.Points)
                            {
                                double effectRelativePosition = startPos + ((point.X / 100.0) * range);
                                double proportion             = ColorGradient.GetProportionOfColorAt(effectRelativePosition, color);
                                point.Y *= proportion;
                            }
                            pulse.LevelCurve    = newCurve;
                            pulse.ColorGradient = new ColorGradient(color);
                            pulseData           = pulse.Render();
                            pulseData.OffsetAllCommandsByTime(current);
                            _elementData.Add(pulseData);
                        }
                    }
                    else
                    {
                        pulse.ColorGradient = ColorGradient.GetSubGradient(startPos, endPos);
                        pulseData           = pulse.Render();
                        pulseData.OffsetAllCommandsByTime(current);
                        _elementData.Add(pulseData);
                    }
                    break;

                case SpinColorHandling.StaticColor:
                    pulse.ColorGradient = StaticColorGradient;
                    pulseData           = pulse.Render();
                    pulseData.OffsetAllCommandsByTime(current);
                    _elementData.Add(pulseData);
                    break;

                case SpinColorHandling.ColorAcrossItems:
                    if (discreteColors)
                    {
                        List <Tuple <Color, float> > colorsAtPosition = ColorGradient.GetDiscreteColorsAndProportionsAt(targetElementPosition / 100.0);
                        foreach (Tuple <Color, float> colorProportion in colorsAtPosition)
                        {
                            if (tokenSource != null && tokenSource.IsCancellationRequested)
                            {
                                return;
                            }

                            float proportion = colorProportion.Item2;
                            // scale all levels of the pulse curve by the proportion that is applicable to this color
                            Curve newCurve = new Curve(pulse.LevelCurve.Points);
                            foreach (PointPair pointPair in newCurve.Points)
                            {
                                pointPair.Y *= proportion;
                            }
                            pulse.LevelCurve    = newCurve;
                            pulse.ColorGradient = new ColorGradient(colorProportion.Item1);
                            pulseData           = pulse.Render();
                            pulseData.OffsetAllCommandsByTime(current);
                            _elementData.Add(pulseData);
                        }
                    }
                    else
                    {
                        pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(targetElementPosition / 100.0));
                        pulseData           = pulse.Render();
                        pulseData.OffsetAllCommandsByTime(current);
                        _elementData.Add(pulseData);
                    }
                    break;
                }

                lastTargetedNode = currentNode;
            }

            _elementData = EffectIntents.Restrict(_elementData, TimeSpan.Zero, TimeSpan);
        }
Ejemplo n.º 10
0
        private EffectIntents RenderElement(IElementNode node, double positionWithinGroup, bool discreteColors,
                                            List <IndividualTwinkleDetails> twinkles = null)
        {
            if (twinkles == null)
            {
                twinkles = GenerateTwinkleData();
            }

            EffectIntents result = new EffectIntents();

            // render the flat 'minimum value' across the entire effect
            //Pulse.Pulse pulse = new Pulse.Pulse();
            //pulse.TargetNodes = new ElementNode[] {node};
            //pulse.TimeSpan = TimeSpan;

            double        minPulseValue = MinimumLevel * 100.0;
            EffectIntents pulseData;

            // figure out what color gradient to use for the pulse
            if (MinimumLevel > 0.0)
            {
                switch (ColorHandling)
                {
                case TwinkleColorHandling.GradientForEachPulse:
                    if (discreteColors)
                    {
                        List <Tuple <Color, float> > colorProportions = ColorGradient.GetDiscreteColorsAndProportionsAt(0);
                        foreach (Tuple <Color, float> colorProportion in colorProportions)
                        {
                            double value = minPulseValue * colorProportion.Item2;
                            //pulse.LevelCurve = new Curve(new PointPairList(new double[] {0, 100}, new [] {value, value}));
                            //pulse.ColorGradient = new ColorGradient(colorProportion.Item1);
                            //pulseData = pulse.Render();
                            pulseData = PulseRenderer.RenderNode(node, new Curve(new PointPairList(new double[] { 0, 100 }, new[] { value, value })), new ColorGradient(colorProportion.Item1), TimeSpan, HasDiscreteColors);
                            result.Add(pulseData);
                        }
                    }
                    else
                    {
                        //pulse.LevelCurve = new Curve(new PointPairList(new double[] {0, 100}, new double[] {minPulseValue, minPulseValue}));
                        //pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(0));
                        //pulseData = pulse.Render();
                        pulseData = PulseRenderer.RenderNode(node, new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { minPulseValue, minPulseValue })), new ColorGradient(ColorGradient.GetColorAt(0)), TimeSpan, HasDiscreteColors);
                        result.Add(pulseData);
                    }
                    break;

                case TwinkleColorHandling.GradientThroughWholeEffect:
                    //pulse.LevelCurve = new Curve(new PointPairList(new double[] {0, 100}, new double[] {minPulseValue, minPulseValue}));
                    //pulse.ColorGradient = ColorGradient;
                    //pulseData = pulse.Render();
                    pulseData = PulseRenderer.RenderNode(node, new Curve(new PointPairList(new double[] { 0, 100 }, new [] { minPulseValue, minPulseValue })), ColorGradient, TimeSpan, HasDiscreteColors);
                    result.Add(pulseData);
                    break;

                case TwinkleColorHandling.StaticColor:
                    //pulse.LevelCurve = new Curve(new PointPairList(new double[] {0, 100}, new double[] {minPulseValue, minPulseValue}));
                    //pulse.ColorGradient = StaticColorGradient;
                    //pulseData = pulse.Render();
                    pulseData = PulseRenderer.RenderNode(node, new Curve(new PointPairList(new double[] { 0, 100 }, new [] { minPulseValue, minPulseValue })), StaticColorGradient, TimeSpan, HasDiscreteColors);
                    result.Add(pulseData);
                    break;

                case TwinkleColorHandling.ColorAcrossItems:
                    if (discreteColors)
                    {
                        List <Tuple <Color, float> > colorsAtPosition = ColorGradient.GetDiscreteColorsAndProportionsAt(positionWithinGroup);
                        foreach (Tuple <Color, float> colorProportion in colorsAtPosition)
                        {
                            double value = minPulseValue * colorProportion.Item2;
                            //pulse.LevelCurve = new Curve(new PointPairList(new double[] {0, 100}, new double[] {value, value}));
                            //pulse.ColorGradient = new ColorGradient(colorProportion.Item1);
                            //pulseData = pulse.Render();
                            pulseData = PulseRenderer.RenderNode(node, new Curve(new PointPairList(new double[] { 0, 100 }, new[] { value, value })), new ColorGradient(colorProportion.Item1), TimeSpan, HasDiscreteColors);
                            result.Add(pulseData);
                        }
                    }
                    else
                    {
                        //pulse.LevelCurve = new Curve(new PointPairList(new double[] {0, 100}, new double[] {minPulseValue, minPulseValue}));
                        //pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup));
                        //pulseData = pulse.Render();
                        pulseData = PulseRenderer.RenderNode(node, new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { minPulseValue, minPulseValue })), new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup)), TimeSpan, HasDiscreteColors);
                        result.Add(pulseData);
                    }
                    break;
                }
            }


            _colorValueSet.Clear();

            if (!IsElementDiscrete(node))
            {
                _colorValueSet.Add(Color.Empty, new ColorValue[(int)(TimeSpan.TotalMilliseconds / FrameTime)]);
            }

            // render all the individual twinkles
            foreach (IndividualTwinkleDetails twinkle in twinkles)
            {
                {
                    var curve = new Curve(new PointPairList(new double[] { 0, 50, 100 }, new[] { twinkle.CurvePoints[0], twinkle.CurvePoints[1], twinkle.CurvePoints[2] }));
                    // figure out what color gradient to use for the pulse
                    switch (ColorHandling)
                    {
                    case TwinkleColorHandling.GradientForEachPulse:
                        RenderPulseSegment(twinkle.StartTime, twinkle.Duration, curve, ColorGradient, node);
                        break;

                    case TwinkleColorHandling.GradientThroughWholeEffect:
                        double startPos = (twinkle.StartTime.Ticks / (double)TimeSpan.Ticks);
                        double endPos   = ((twinkle.StartTime + twinkle.Duration).Ticks / (double)TimeSpan.Ticks);

                        if (discreteColors)
                        {
                            double range = endPos - startPos;
                            if (range <= 0.0)
                            {
                                Logging.Error("Twinkle: bad range: " + range + " (SP=" + startPos + ", EP=" + endPos + ")");
                                break;
                            }

                            ColorGradient cg = ColorGradient.GetSubGradientWithDiscreteColors(startPos, endPos);

                            foreach (Color color in cg.GetColorsInGradient())
                            {
                                curve = new Curve(curve.Points);
                                foreach (PointPair point in curve.Points)
                                {
                                    double effectRelativePosition = startPos + ((point.X / 100.0) * range);
                                    double proportion             = ColorGradient.GetProportionOfColorAt(effectRelativePosition, color);
                                    point.Y *= proportion;
                                }
                                RenderPulseSegment(twinkle.StartTime, twinkle.Duration, curve, new ColorGradient(color), node);
                                //pulseData = PulseRenderer.RenderNode(node, curve, new ColorGradient(color), twinkle.Duration, HasDiscreteColors);
                                //pulseData.OffsetAllCommandsByTime(twinkle.StartTime);
                                //result.Add(pulseData);
                            }
                        }
                        else
                        {
                            RenderPulseSegment(twinkle.StartTime, twinkle.Duration, curve, ColorGradient.GetSubGradient(startPos, endPos), node);
                        }
                        break;

                    case TwinkleColorHandling.StaticColor:
                        RenderPulseSegment(twinkle.StartTime, twinkle.Duration, curve, StaticColorGradient, node);
                        break;

                    case TwinkleColorHandling.ColorAcrossItems:
                        if (discreteColors)
                        {
                            List <Tuple <Color, float> > colorsAtPosition = ColorGradient.GetDiscreteColorsAndProportionsAt(positionWithinGroup);
                            foreach (Tuple <Color, float> colorProportion in colorsAtPosition)
                            {
                                float proportion = colorProportion.Item2;
                                // scale all levels of the twinkle curve by the proportion that is applicable to this color
                                curve = new Curve(curve.Points);
                                foreach (PointPair pointPair in curve.Points)
                                {
                                    pointPair.Y *= proportion;
                                }

                                RenderPulseSegment(twinkle.StartTime, twinkle.Duration, curve, new ColorGradient(colorProportion.Item1), node);
                                //pulseData = PulseRenderer.RenderNode(node, curve, new ColorGradient(colorProportion.Item1), twinkle.Duration, HasDiscreteColors);
                                //pulseData.OffsetAllCommandsByTime(twinkle.StartTime);
                                //result.Add(pulseData);
                            }
                        }
                        else
                        {
                            RenderPulseSegment(twinkle.StartTime, twinkle.Duration, curve, new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup)), node);
                        }
                        break;
                    }
                }
            }

            foreach (var set in _colorValueSet)
            {
                if (set.Key == Color.Empty)
                {
                    var data = CreateIntentForValues(set.Value);
                    if (node.IsLeaf)
                    {
                        result.AddIntentForElement(node.Element.Id, data, TimeSpan.Zero);
                    }
                    else
                    {
                        foreach (var leafNode in node.GetLeafEnumerator())
                        {
                            result.AddIntentForElement(leafNode.Element.Id, data, TimeSpan.Zero);
                        }
                    }
                }
                else
                {
                    var data = CreateDiscreteIntentForValues(set.Value);
                    if (node.IsLeaf)
                    {
                        result.AddIntentForElement(node.Element.Id, data, TimeSpan.Zero);
                    }
                    else
                    {
                        foreach (var leafNode in node.GetLeafEnumerator())
                        {
                            result.AddIntentForElement(leafNode.Element.Id, data, TimeSpan.Zero);
                        }
                    }
                }
            }


            return(result);
        }