private void GenerateExtendedStaticPulse(ElementNode target, Curve newCurve, ColorGradient gradient, TimeSpan duration, TimeSpan offset) { var result = PulseRenderer.RenderNode(target, newCurve, gradient, duration, HasDiscreteColors); result.OffsetAllCommandsByTime(offset); _elementData.Add(result); }
private void RenderElement(GradientLevelPair gradientLevelPair, TimeSpan startTime, TimeSpan interval, ElementNode element, EffectIntents effectIntents) { var result = PulseRenderer.RenderNode(element, gradientLevelPair.Curve, gradientLevelPair.ColorGradient, interval, HasDiscreteColors); result.OffsetAllCommandsByTime(startTime); effectIntents.Add(result); }
private void DoRendering(CancellationTokenSource tokenSource = null) { 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 (EnableDefaultLevel) { 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) { double level = DefaultLevel * 100.0; // figure out what color gradient to use for the pulse switch (ColorHandling) { case SpinColorHandling.GradientForEachPulse: pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new [] { level, level })), StaticColorGradient, TimeSpan, HasDiscreteColors, true); _elementData.Add(pulseData); break; case SpinColorHandling.GradientThroughWholeEffect: pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new [] { level, level })), ColorGradient, TimeSpan, HasDiscreteColors, true); _elementData.Add(pulseData); break; case SpinColorHandling.StaticColor: pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new[] { level, level })), StaticColorGradient, TimeSpan, HasDiscreteColors, true); _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; pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new [] { value, value })), new ColorGradient(colorProportion.Item1), TimeSpan, HasDiscreteColors, true); _elementData.Add(pulseData); } } else { pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new double[] { level, level })), new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup)), TimeSpan, HasDiscreteColors, true); _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 })); } //TODO: get a better increment time. doing it every X ms is..... shitty at best. //Less crappy is try to make some adjustment if there are a lot of nodes in a shorter time to sample more often. //A hard and fast 2ms was leaving gaps in larger node counts var sampleMs = revTimeSpan.TotalMilliseconds / targetNodeCount / 2.0; if (sampleMs < .25) { sampleMs = .25; } else if (sampleMs > 2) { sampleMs = 2; } TimeSpan increment = TimeSpan.FromTicks((long)(sampleMs * TimeSpan.TicksPerMillisecond)); // 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); // figure out what color gradient to use for the pulse switch (ColorHandling) { case SpinColorHandling.GradientForEachPulse: pulseData = PulseRenderer.RenderNode(currentNode, new Curve(PulseCurve), ColorGradient, pulseTimeSpan, HasDiscreteColors); 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(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; } pulseData = PulseRenderer.RenderNode(currentNode, newCurve, new ColorGradient(color), pulseTimeSpan, HasDiscreteColors); pulseData.OffsetAllCommandsByTime(current); _elementData.Add(pulseData); } } else { pulseData = PulseRenderer.RenderNode(currentNode, new Curve(PulseCurve), ColorGradient.GetSubGradient(startPos, endPos), pulseTimeSpan, HasDiscreteColors); pulseData.OffsetAllCommandsByTime(current); _elementData.Add(pulseData); } break; case SpinColorHandling.StaticColor: pulseData = PulseRenderer.RenderNode(currentNode, new Curve(PulseCurve), StaticColorGradient, pulseTimeSpan, HasDiscreteColors); 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(PulseCurve.Points); foreach (PointPair pointPair in newCurve.Points) { pointPair.Y *= proportion; } pulseData = PulseRenderer.RenderNode(currentNode, newCurve, new ColorGradient(colorProportion.Item1), pulseTimeSpan, HasDiscreteColors); pulseData.OffsetAllCommandsByTime(current); _elementData.Add(pulseData); } } else { pulseData = PulseRenderer.RenderNode(currentNode, new Curve(PulseCurve), new ColorGradient(ColorGradient.GetColorAt(targetElementPosition / 100.0)), pulseTimeSpan, HasDiscreteColors); pulseData.OffsetAllCommandsByTime(current); _elementData.Add(pulseData); } break; } lastTargetedNode = currentNode; } _elementData = EffectIntents.Restrict(_elementData, TimeSpan.Zero, TimeSpan); }
private EffectIntents RenderElement(ElementNode 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; } } // 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] })); 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: //pulse.ColorGradient = ColorGradient; //pulseData = pulse.Render(); pulseData = PulseRenderer.RenderNode(node, curve, ColorGradient, twinkle.Duration, HasDiscreteColors); pulseData.OffsetAllCommandsByTime(twinkle.StartTime); result.Add(pulseData); 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; } //pulse.LevelCurve = newCurve; //pulse.ColorGradient = new ColorGradient(color); //pulseData = pulse.Render(); pulseData = PulseRenderer.RenderNode(node, curve, new ColorGradient(color), twinkle.Duration, HasDiscreteColors); pulseData.OffsetAllCommandsByTime(twinkle.StartTime); result.Add(pulseData); } } else { //pulse.ColorGradient = ColorGradient.GetSubGradient(startPos, endPos); //pulseData = pulse.Render(); pulseData = PulseRenderer.RenderNode(node, curve, ColorGradient.GetSubGradient(startPos, endPos), twinkle.Duration, HasDiscreteColors); pulseData.OffsetAllCommandsByTime(twinkle.StartTime); result.Add(pulseData); } break; case TwinkleColorHandling.StaticColor: //pulse.ColorGradient = StaticColorGradient; //pulseData = pulse.Render(); pulseData = PulseRenderer.RenderNode(node, curve, StaticColorGradient, twinkle.Duration, HasDiscreteColors); 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 = new Curve(curve.Points); foreach (PointPair pointPair in curve.Points) { pointPair.Y *= proportion; } //pulse.LevelCurve = newCurve; //pulse.ColorGradient = new ColorGradient(colorProportion.Item1); //pulseData = pulse.Render(); pulseData = PulseRenderer.RenderNode(node, curve, new ColorGradient(colorProportion.Item1), twinkle.Duration, HasDiscreteColors); pulseData.OffsetAllCommandsByTime(twinkle.StartTime); result.Add(pulseData); } } else { //pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup)); //pulseData = pulse.Render(); pulseData = PulseRenderer.RenderNode(node, curve, new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup)), twinkle.Duration, HasDiscreteColors); pulseData.OffsetAllCommandsByTime(twinkle.StartTime); result.Add(pulseData); } break; } } } return(result); }
private void RenderMovement(List <IElementNode[]> renderNodes, CancellationTokenSource tokenSource) { double previousMovement = 2.0; TimeSpan startTime = TimeSpan.Zero; TimeSpan timeInterval = TimeSpan.FromMilliseconds(_timeInterval); int intervals = Convert.ToInt32(Math.Ceiling(TimeSpan.TotalMilliseconds / _timeInterval)); int burst = Direction != WipeDirection.DiagonalUp ? 0 : _pulsePercent - 1; List <WipeClass> renderElements = new List <WipeClass>(); for (int i = 0; i < intervals; i++) { double position = (double)100 / intervals * i; double movement = MovementCurve.GetValue(position) / 100; if (previousMovement != movement) { if (renderElements.Count > 0) { renderElements.Last().Duration = startTime - renderElements.Last().StartTime; } WipeClass wc = new WipeClass { ElementIndex = (int)((renderNodes.Count - 1) * movement), StartTime = startTime, Duration = TimeSpan - startTime }; if (ReverseColorDirection) { wc.ReverseColorDirection = previousMovement < movement ? 0 : 1; } renderElements.Add(wc); } previousMovement = movement; startTime += timeInterval; } double pos = ((double)100 / _pulsePercent) / 100; // Now render element foreach (var wipeNode in renderElements) { for (int i = 0; i < _pulsePercent; i++) { double position = wipeNode.ReverseColorDirection - pos * i; if (position < 0) { position = -position; } Color color = _data.ColorGradient.GetColorAt(position); double curveValue = _data.Curve.GetValue(position * 100) / 100; if (wipeNode.ElementIndex - i > 0 && wipeNode.ElementIndex - i + burst < renderNodes.Count) { IElementNode[] elementGroup = renderNodes[wipeNode.ElementIndex - i + burst]; if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } foreach (var item in elementGroup) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } if (item != null) { var result = PulseRenderer.RenderNode(item, curveValue, color, wipeNode.Duration); result.OffsetAllCommandsByTime(wipeNode.StartTime); _elementData.Add(result); } } } } } }
private void RenderCount(List <IElementNode[]> renderNodes, CancellationTokenSource tokenSource) { TimeSpan effectTime = TimeSpan.Zero; int count = 0; double pulseSegment = (TimeSpan.Ticks * ((PulsePercent * ((double)_steps / renderNodes.Count())) / 100)) / PassCount; TimeSpan intervalTime = TimeSpan.FromTicks((long)((TimeSpan.Ticks - pulseSegment) / (renderNodes.Count() * PassCount))); TimeSpan segmentPulse = TimeSpan.FromTicks((long)pulseSegment); while (count < PassCount) { foreach (IElementNode[] item in renderNodes) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } foreach (IElementNode element in item) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } if (element == null) { continue; } EffectIntents result; if (ColorHandling == ColorHandling.GradientThroughWholeEffect) { result = PulseRenderer.RenderNode(element, _data.Curve, _data.ColorGradient, segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); if (WipeOff && count == 0 && result.Any()) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(element, effectIntent, HasDiscreteColors)); } } if (WipeOn && result.Any() && count == PassCount - 1) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(element, effectIntent, TimeSpan, HasDiscreteColors)); } } _elementData.Add(result); } else { double positionWithinGroup = (double)(1.0 / (TimeSpan.Ticks - segmentPulse.Ticks)) * (effectTime.Ticks); if (ColorAcrossItemPerCount) { positionWithinGroup = positionWithinGroup * PassCount % 1; } if (HasDiscreteColors) { List <Tuple <Color, float> > colorsAtPosition = ColorGradient.GetDiscreteColorsAndProportionsAt(positionWithinGroup); 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(Curve.Points); foreach (PointPair pointPair in newCurve.Points) { pointPair.Y *= proportion; } result = PulseRenderer.RenderNode(element, newCurve, new ColorGradient(colorProportion.Item1), segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); if (WipeOff && count == 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(element, effectIntent, HasDiscreteColors, new ColorGradient(colorProportion.Item1))); } } if (result.Count > 0) { _elementData.Add(result); } if (WipeOn && count == PassCount - 1) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(element, effectIntent, TimeSpan, HasDiscreteColors, new ColorGradient(colorProportion.Item1))); } } } } else { result = PulseRenderer.RenderNode(element, _data.Curve, new ColorGradient(_data.ColorGradient.GetColorAt(positionWithinGroup)), segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); if (WipeOff && count == 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(element, effectIntent, HasDiscreteColors)); } } if (WipeOn && count == PassCount - 1) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(element, effectIntent, TimeSpan, HasDiscreteColors)); } } _elementData.Add(result); } } } effectTime += intervalTime; } count++; } }
private void RenderPulseLength(List <IElementNode[]> renderNodes, CancellationTokenSource tokenSource) { TimeSpan effectTime = TimeSpan.Zero; double intervals = (double)PulseTime / renderNodes.Count(); var intervalTime = TimeSpan.FromMilliseconds(intervals); // the calculation above blows up render time/memory as count goes up, try this.. // also fails if intervals is less than half a ms and intervalTime then gets 0 intervalTime = TimeSpan.FromMilliseconds(Math.Max(intervalTime.TotalMilliseconds, 5)); TimeSpan segmentPulse = TimeSpan.FromMilliseconds(PulseTime); while (effectTime < TimeSpan) { foreach (var item in renderNodes) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } foreach (IElementNode element in item) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } if (element == null) { continue; } EffectIntents result; if (ColorHandling == ColorHandling.GradientThroughWholeEffect) { result = PulseRenderer.RenderNode(element, _data.Curve, _data.ColorGradient, segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); _elementData.Add(result); } else { double positionWithinGroup = (double)(1.0 / (TimeSpan.Ticks - segmentPulse.Ticks)) * (effectTime.Ticks); if (ColorAcrossItemPerCount) { positionWithinGroup = positionWithinGroup * PassCount % 1; } if (HasDiscreteColors) { List <Tuple <Color, float> > colorsAtPosition = ColorGradient.GetDiscreteColorsAndProportionsAt(positionWithinGroup); 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(Curve.Points); foreach (PointPair pointPair in newCurve.Points) { pointPair.Y *= proportion; } result = PulseRenderer.RenderNode(element, newCurve, new ColorGradient(colorProportion.Item1), segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); } } else { result = PulseRenderer.RenderNode(element, _data.Curve, new ColorGradient(_data.ColorGradient.GetColorAt(positionWithinGroup)), segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); _elementData.Add(result); } } } effectTime += intervalTime; if (effectTime >= TimeSpan) { return; } } } }
private void RenderBurst(CancellationTokenSource tokenSource, WipeDirection direction) { switch (direction) { case WipeDirection.In: case WipeDirection.Out: break; default: throw new InvalidOperationException("the RenderBurst method should only be called for Wipe Directions In and Out"); break; } var burstNodes = TargetNodes.SelectMany(x => x.GetLeafEnumerator()) .Select(s => { var prop = s.Properties.Get(LocationDescriptor._typeId); if (prop != null) { return(new Tuple <ElementNode, int, int, int>(s, ((LocationData)prop.ModuleData).X, ((LocationData)prop.ModuleData).Y, ((LocationData)prop.ModuleData).Z)); } return(new Tuple <ElementNode, int, int, int>(null, -1, -1, -1)); //return null }) .Where(s => s.Item2 > 0) // Ignore the pseudo null values .ToList(); if (!burstNodes.Any()) { return; } var maxX = burstNodes.Max(m => m.Item2); var maxY = burstNodes.Max(m => m.Item3); var minX = burstNodes.Min(m => m.Item2); var minY = burstNodes.Min(m => m.Item3); var Steps = (int)(Math.Max(maxX - minX, maxY - minY) / 2); List <Tuple <int, ElementNode[]> > groups = new List <Tuple <int, ElementNode[]> >(); for (int i = 0; i < Steps; i++) { List <ElementNode> elements = new List <ElementNode>(); var xNodes = burstNodes.Where(x => (x.Item2 == minX + i || x.Item2 == maxX - i) ) .Select(s => s.Item1).ToList(); var yNodes = burstNodes.Where(x => ( x.Item3 == minY + i || x.Item3 == maxY - i) ) .Select(s => s.Item1).ToList(); yNodes.RemoveAll(s => { var prop = s.Properties.Get(LocationDescriptor._typeId); if (prop != null) { return(((LocationData)prop.ModuleData).X < minX + i || ((LocationData)prop.ModuleData).X > maxX - i); } return(false); }); xNodes.RemoveAll(s => { var prop = s.Properties.Get(LocationDescriptor._typeId); if (prop != null) { return(((LocationData)prop.ModuleData).Y < minY + i || ((LocationData)prop.ModuleData).Y > maxY - i); } return(false); }); elements.AddRange(yNodes); elements.AddRange(xNodes); groups.Add(new Tuple <int, ElementNode[]>(i, elements.ToArray())); } List <ElementNode[]> renderNodes = new List <ElementNode[]>(); switch (direction) { case WipeDirection.In: renderNodes = groups.OrderBy(o => o.Item1).Select(s => s.Item2).ToList(); break; case WipeDirection.Out: renderNodes = groups.OrderByDescending(o => o.Item1).Select(s => s.Item2).ToList(); break; } //var pulse = new Pulse.Pulse(); if (renderNodes != null && renderNodes.Any()) { TimeSpan effectTime = TimeSpan.Zero; if (WipeByCount) { int count = 0; double pulseSegment = TimeSpan.Ticks / (double)PassCount * (PulsePercent / 100); TimeSpan intervalTime = TimeSpan.FromTicks((long)((TimeSpan.Ticks - pulseSegment) / (renderNodes.Count() * PassCount))); TimeSpan segmentPulse = TimeSpan.FromTicks((long)pulseSegment); while (count < PassCount) { foreach (var item in renderNodes) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } EffectIntents result; foreach (ElementNode element in item) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } if (element != null) { //pulse.TimeSpan = segmentPulse; //pulse.ColorGradient = _data.ColorGradient; //pulse.LevelCurve = _data.Curve; //pulse.TargetNodes = new ElementNode[] { element }; //result = pulse.Render(); result = PulseRenderer.RenderNode(element, _data.Curve, _data.ColorGradient, segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); bool discreteElement = HasDiscreteColors && ColorModule.isElementNodeDiscreteColored(element); _elementData.Add(IntentBuilder.ConvertToStaticArrayIntents(result, TimeSpan, discreteElement)); } } effectTime += intervalTime; } count++; } } else { double intervals = (double)PulseTime / (double)renderNodes.Count(); var intervalTime = TimeSpan.FromMilliseconds(intervals); // the calculation above blows up render time/memory as count goes up, try this.. // also fails if intervals is less than half a ms and intervalTime then gets 0 intervalTime = TimeSpan.FromMilliseconds(Math.Max(intervalTime.TotalMilliseconds, 5)); TimeSpan segmentPulse = TimeSpan.FromMilliseconds(PulseTime); while (effectTime < TimeSpan) { foreach (var item in renderNodes) { EffectIntents result; if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } foreach (ElementNode element in item) { if (element != null) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } //pulse.TimeSpan = segmentPulse; //pulse.ColorGradient = _data.ColorGradient; //pulse.LevelCurve = _data.Curve; //pulse.TargetNodes = new ElementNode[] { element }; //result = pulse.Render(); result = PulseRenderer.RenderNode(element, _data.Curve, _data.ColorGradient, segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); bool discreteElement = HasDiscreteColors && ColorModule.isElementNodeDiscreteColored(element); _elementData.Add(IntentBuilder.ConvertToStaticArrayIntents(result, TimeSpan, discreteElement)); } } effectTime += intervalTime; if (effectTime >= TimeSpan) { return; } } } } } }
private void RenderNonBurst(CancellationTokenSource tokenSource, IEnumerable <IGrouping <int, ElementNode> > renderNodes) { //var pulse = new Pulse.Pulse(); if (renderNodes != null && renderNodes.Any()) { TimeSpan effectTime = TimeSpan.Zero; if (WipeByCount) { int count = 0; double pulseSegment = TimeSpan.Ticks / (double)PassCount * (PulsePercent / 100); TimeSpan intervalTime = TimeSpan.FromTicks((long)((TimeSpan.Ticks - pulseSegment) / (renderNodes.Count() * PassCount))); TimeSpan segmentPulse = TimeSpan.FromTicks((long)pulseSegment); while (count < PassCount) { foreach (var item in renderNodes) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } EffectIntents result; foreach (ElementNode element in item) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } if (element != null) { //pulse.TimeSpan = segmentPulse; //pulse.ColorGradient = _data.ColorGradient; //pulse.LevelCurve = _data.Curve; //pulse.TargetNodes = new ElementNode[] { element }; //result = pulse.Render(); result = PulseRenderer.RenderNode(element, _data.Curve, _data.ColorGradient, segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); bool discreteElement = HasDiscreteColors && ColorModule.isElementNodeDiscreteColored(element); _elementData.Add(IntentBuilder.ConvertToStaticArrayIntents(result, TimeSpan, discreteElement)); } } effectTime += intervalTime; } count++; } } else { double intervals = (double)PulseTime / (double)renderNodes.Count(); var intervalTime = TimeSpan.FromMilliseconds(intervals); // the calculation above blows up render time/memory as count goes up, try this.. // also fails if intervals is less than half a ms and intervalTime then gets 0 intervalTime = TimeSpan.FromMilliseconds(Math.Max(intervalTime.TotalMilliseconds, 5)); TimeSpan segmentPulse = TimeSpan.FromMilliseconds(PulseTime); while (effectTime < TimeSpan) { foreach (var item in renderNodes) { EffectIntents result; if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } foreach (ElementNode element in item) { if (element != null) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } //pulse.TimeSpan = segmentPulse; //pulse.ColorGradient = _data.ColorGradient; //pulse.LevelCurve = _data.Curve; //pulse.TargetNodes = new ElementNode[] { element }; //result = pulse.Render(); result = PulseRenderer.RenderNode(element, _data.Curve, _data.ColorGradient, segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); bool discreteElement = HasDiscreteColors && ColorModule.isElementNodeDiscreteColored(element); _elementData.Add(IntentBuilder.ConvertToStaticArrayIntents(result, TimeSpan, discreteElement)); } } effectTime += intervalTime; if (effectTime >= TimeSpan) { return; } } } } } }
//private void GenerateExtendedStaticPulse(ElementNode target, IIntentNode intentNode, ColorGradient gradient=null) //{ // if (intentNode == null || intentNode.EndTime >= TimeSpan) return; // var lightingIntent = intentNode.Intent as LightingIntent; // if (lightingIntent != null && lightingIntent.EndValue.Intensity > 0) // { // var newCurve = new Curve(lightingIntent.EndValue.Intensity*100); // GenerateExtendedStaticPulse(target, newCurve, gradient ?? new ColorGradient(lightingIntent.EndValue.FullColor), // TimeSpan - intentNode.EndTime, intentNode.EndTime); // } // else // { // var discreteIntent = intentNode.Intent as DiscreteLightingIntent; // if (discreteIntent != null && discreteIntent.EndValue.Intensity > 0) // { // var newCurve = new Curve(discreteIntent.EndValue.Intensity*100); // GenerateExtendedStaticPulse(target, newCurve, gradient ?? new ColorGradient(discreteIntent.EndValue.FullColor), // TimeSpan - intentNode.EndTime, intentNode.EndTime); // } // } //} //private void GenerateExtendedStaticPulse(ElementNode target, Curve newCurve, ColorGradient gradient, TimeSpan duration, TimeSpan offset) //{ // var result = PulseRenderer.RenderNode(target, newCurve, gradient, duration, HasDiscreteColors); // result.OffsetAllCommandsByTime(offset); // _elementData.Add(result); //} //private void GenerateStartingStaticPulse(ElementNode target, IIntentNode intentNode, ColorGradient gradient=null) //{ // if (intentNode == null || intentNode.StartTime <= TimeSpan.Zero) return; // var lightingIntent = intentNode.Intent as LightingIntent; // if (lightingIntent != null && lightingIntent.StartValue.Intensity > 0) // { // var newCurve = new Curve(lightingIntent.StartValue.Intensity*100); // GenerateStartingStaticPulse(target,newCurve, gradient ?? new ColorGradient(lightingIntent.StartValue.FullColor), intentNode.StartTime); // } // else // { // var discreteIntent = intentNode.Intent as DiscreteLightingIntent; // if (discreteIntent != null && discreteIntent.StartValue.Intensity > 0) // { // var newCurve = new Curve(discreteIntent.StartValue.Intensity*100); // GenerateStartingStaticPulse(target, newCurve, gradient ?? new ColorGradient(discreteIntent.StartValue.FullColor), // intentNode.StartTime); // } // } //} //private void GenerateStartingStaticPulse(ElementNode target, Curve newCurve, ColorGradient gradient, TimeSpan time) //{ // var result = PulseRenderer.RenderNode(target, newCurve, gradient, time, HasDiscreteColors); // _elementData.Add(result); //} private void GeneratePulse(ElementNode target, TimeSpan startTime, TimeSpan duration, double currentMovementPosition) { EffectIntents result = null; // figure out what color gradient to use for the pulse switch (ColorHandling) { case ChaseColorHandling.GradientForEachPulse: result = PulseRenderer.RenderNode(target, PulseCurve, ColorGradient, duration, HasDiscreteColors); result.OffsetAllCommandsByTime(startTime); if (ExtendPulseToStart && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(target, effectIntent, HasDiscreteColors)); } } _elementData.Add(result); if (ExtendPulseToEnd && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(target, effectIntent, TimeSpan, HasDiscreteColors)); } } 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 (HasDiscreteColors) { 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; } result = PulseRenderer.RenderNode(target, newCurve, new ColorGradient(color), duration, HasDiscreteColors); result.OffsetAllCommandsByTime(startTime); if (ExtendPulseToStart && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(target, effectIntent, HasDiscreteColors, new ColorGradient(color))); } } if (result.Count > 0) { _elementData.Add(result); } if (ExtendPulseToEnd && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(target, effectIntent, TimeSpan, HasDiscreteColors, new ColorGradient(color))); } } } } else { result = PulseRenderer.RenderNode(target, PulseCurve, ColorGradient.GetSubGradient(startPos, endPos), duration, HasDiscreteColors); result.OffsetAllCommandsByTime(startTime); if (ExtendPulseToStart && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(target, effectIntent, HasDiscreteColors, ColorGradient.GetSubGradient(0, startPos))); } } _elementData.Add(result); if (ExtendPulseToEnd && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(target, effectIntent, TimeSpan, HasDiscreteColors, ColorGradient.GetSubGradient(endPos, 1))); } } } break; case ChaseColorHandling.StaticColor: result = PulseRenderer.RenderNode(target, PulseCurve, StaticColorGradient, duration, HasDiscreteColors); result.OffsetAllCommandsByTime(startTime); if (ExtendPulseToStart && result.Count > 0) { var intent = result.FirstOrDefault().Value.FirstOrDefault(); _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(target, intent, HasDiscreteColors)); } _elementData.Add(result); if (ExtendPulseToEnd && result.Count > 0) { var intent = result.FirstOrDefault().Value.LastOrDefault(); _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(target, intent, TimeSpan, HasDiscreteColors)); } break; case ChaseColorHandling.ColorAcrossItems: if (HasDiscreteColors) { 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; } result = PulseRenderer.RenderNode(target, newCurve, new ColorGradient(colorProportion.Item1), duration, HasDiscreteColors); result.OffsetAllCommandsByTime(startTime); if (ExtendPulseToStart && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(target, effectIntent, HasDiscreteColors, new ColorGradient(colorProportion.Item1))); } } if (result.Count > 0) { _elementData.Add(result); } if (ExtendPulseToEnd && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(target, effectIntent, TimeSpan, HasDiscreteColors, new ColorGradient(colorProportion.Item1))); } } } } else { result = PulseRenderer.RenderNode(target, PulseCurve, new ColorGradient(ColorGradient.GetColorAt(currentMovementPosition / 100.0)), duration, HasDiscreteColors); result.OffsetAllCommandsByTime(startTime); if (ExtendPulseToStart && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(target, effectIntent, HasDiscreteColors)); } } _elementData.Add(result); if (ExtendPulseToEnd && result.Count > 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(target, effectIntent, TimeSpan, HasDiscreteColors)); } } } break; } }
private void DoRendering(CancellationTokenSource tokenSource = null) { List <ElementNode> renderNodes = GetNodesToRenderOn(); int targetNodeCount = renderNodes.Count; // apply the 'background' values to all targets if the level is supposed to be enabled if (EnableDefaultLevel) { int i = 0; foreach (ElementNode target in renderNodes) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } if (target != null) { bool discreteColors = ColorModule.isElementNodeDiscreteColored(target); double level = DefaultLevel * 100.0; // figure out what color gradient to use for the pulse EffectIntents pulseData; switch (ColorHandling) { case ChaseColorHandling.GradientForEachPulse: pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new[] { level, level })), StaticColorGradient, TimeSpan, HasDiscreteColors, true); _elementData.Add(pulseData); break; case ChaseColorHandling.GradientThroughWholeEffect: pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new[] { level, level })), ColorGradient, TimeSpan, HasDiscreteColors, true); _elementData.Add(pulseData); break; case ChaseColorHandling.StaticColor: pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new[] { level, level })), StaticColorGradient, TimeSpan, HasDiscreteColors, true); _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; pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new[] { value, value })), new ColorGradient(colorProportion.Item1), TimeSpan, HasDiscreteColors, true); _elementData.Add(pulseData); } } else { pulseData = PulseRenderer.RenderNode(target, new Curve(new PointPairList(new double[] { 0, 100 }, new [] { level, level })), new ColorGradient(ColorGradient.GetColorAt(positionWithinGroup)), TimeSpan, HasDiscreteColors, true); _elementData.Add(pulseData); } break; } i++; } } } // the total chase time TimeSpan chaseTime = TimeSpan.FromMilliseconds(TimeSpan.TotalMilliseconds - PulseOverlap); if (chaseTime.TotalMilliseconds <= 0) { chaseTime = TimeSpan.FromMilliseconds(1); } //TODO: get a better increment time. doing it every X ms is..... shitty at best. //Less crappy is try to make some adjustment if there are a lot of nodes in a shorter time to sample more often. //A hard and fast 2ms was leaving gaps in larger node counts var sampleMs = chaseTime.TotalMilliseconds / targetNodeCount / 2.0; if (sampleMs < .25) { sampleMs = .25; } else if (sampleMs > 2) { sampleMs = 2; } TimeSpan increment = TimeSpan.FromTicks((long)(sampleMs * TimeSpan.TicksPerMillisecond)); // 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 = (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, ChaseMovement.GetValue(100)); } _elementData = EffectIntents.Restrict(_elementData, TimeSpan.Zero, TimeSpan); }
private void RenderNonBurst(CancellationTokenSource tokenSource, IEnumerable <IGrouping <int, ElementNode> > renderNodes) { //var pulse = new Pulse.Pulse(); if (renderNodes != null && renderNodes.Any()) { TimeSpan effectTime = TimeSpan.Zero; if (WipeByCount) { int count = 0; double pulseSegment = TimeSpan.Ticks / (double)PassCount * (PulsePercent / 100); var maxKey = renderNodes.Select(x => x.Key).Max(); var minKey = renderNodes.Select(x => x.Key).Min(); double adjustedMax = maxKey - minKey; TimeSpan totalWipeTime = TimeSpan.FromTicks((long)((TimeSpan.Ticks - pulseSegment) / PassCount)); TimeSpan segmentPulse = TimeSpan.FromTicks((long)pulseSegment); while (count < PassCount) { foreach (var item in renderNodes) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } switch (Direction) { case WipeDirection.Left: case WipeDirection.Up: effectTime = TimeSpan.FromTicks((long)(totalWipeTime.Ticks * (1 - (item.Key - minKey) / adjustedMax) + count * totalWipeTime.Ticks)); break; default: effectTime = TimeSpan.FromTicks((long)(totalWipeTime.Ticks * (item.Key - minKey) / adjustedMax + count * totalWipeTime.Ticks)); break; } foreach (ElementNode element in item) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } if (element != null) { EffectIntents result; if (ColorHandling == ColorHandling.GradientThroughWholeEffect) { result = PulseRenderer.RenderNode(element, _data.Curve, _data.ColorGradient, segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); if (WipeOff && count == 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(element, effectIntent, HasDiscreteColors)); } } _elementData.Add(result); if (WipeOn && count == PassCount - 1) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(element, effectIntent, TimeSpan, HasDiscreteColors)); } } } else { double positionWithinGroup = effectTime.Ticks / (double)totalWipeTime.Ticks; if (HasDiscreteColors) { List <Tuple <Color, float> > colorsAtPosition = ColorGradient.GetDiscreteColorsAndProportionsAt(positionWithinGroup); 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(Curve.Points); foreach (PointPair pointPair in newCurve.Points) { pointPair.Y *= proportion; } result = PulseRenderer.RenderNode(element, newCurve, new ColorGradient(colorProportion.Item1), segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); if (WipeOff && count == 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(element, effectIntent, HasDiscreteColors, new ColorGradient(colorProportion.Item1))); } } if (result.Count > 0) { _elementData.Add(result); } if (WipeOn && count == PassCount - 1) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(element, effectIntent, TimeSpan, HasDiscreteColors, new ColorGradient(colorProportion.Item1))); } } } } else { result = PulseRenderer.RenderNode(element, _data.Curve, new ColorGradient(_data.ColorGradient.GetColorAt(positionWithinGroup)), segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); if (WipeOff && count == 0) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateStartingStaticPulse(element, effectIntent, HasDiscreteColors)); } } _elementData.Add(result); if (WipeOn && count == PassCount - 1) { foreach (var effectIntent in result.FirstOrDefault().Value) { _elementData.Add(PulseRenderer.GenerateExtendedStaticPulse(element, effectIntent, TimeSpan, HasDiscreteColors)); } } } } } } } count++; } } else { double intervals = (double)PulseTime / (double)renderNodes.Count(); var intervalTime = TimeSpan.FromMilliseconds(intervals); // the calculation above blows up render time/memory as count goes up, try this.. // also fails if intervals is less than half a ms and intervalTime then gets 0 intervalTime = TimeSpan.FromMilliseconds(Math.Max(intervalTime.TotalMilliseconds, 5)); TimeSpan segmentPulse = TimeSpan.FromMilliseconds(PulseTime); while (effectTime < TimeSpan) { foreach (var item in renderNodes) { EffectIntents result; if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } foreach (ElementNode element in item) { if (element != null) { if (tokenSource != null && tokenSource.IsCancellationRequested) { return; } result = PulseRenderer.RenderNode(element, _data.Curve, _data.ColorGradient, segmentPulse, HasDiscreteColors); result.OffsetAllCommandsByTime(effectTime); //bool discreteElement = HasDiscreteColors && ColorModule.isElementNodeDiscreteColored(element); //_elementData.Add(IntentBuilder.ConvertToStaticArrayIntents(result, TimeSpan, discreteElement)); _elementData.Add(result); } } effectTime += intervalTime; if (effectTime >= TimeSpan) { return; } } } } } }
private void GenerateStartingStaticPulse(ElementNode target, Curve newCurve, ColorGradient gradient, TimeSpan time) { var result = PulseRenderer.RenderNode(target, newCurve, gradient, time, HasDiscreteColors); _elementData.Add(result); }