private void GeneratePulse(ElementNode target, TimeSpan startTime, TimeSpan duration, double currentMovementPosition) { EffectIntents result; Pulse.Pulse pulse = new Pulse.Pulse(); pulse.TargetNodes = new ElementNode[] { target }; pulse.TimeSpan = duration; pulse.LevelCurve = new Curve(PulseCurve); // figure out what color gradient to use for the pulse switch (ColorHandling) { case ChaseColorHandling.GradientForEachPulse: pulse.ColorGradient = ColorGradient; break; case ChaseColorHandling.GradientThroughWholeEffect: double startPos = ((double)startTime.Ticks / (double)TimeSpan.Ticks); double endPos = ((double)(startTime + duration).Ticks / (double)TimeSpan.Ticks); if (startPos < 0.0) { startPos = 0.0; } if (endPos > 1.0) { endPos = 1.0; } pulse.ColorGradient = ColorGradient.GetSubGradient(startPos, endPos); break; case ChaseColorHandling.StaticColor: pulse.ColorGradient = new ColorGradient(StaticColor); break; case ChaseColorHandling.ColorAcrossItems: pulse.ColorGradient = new ColorGradient(ColorGradient.GetColorAt(currentMovementPosition / 100.0)); break; } result = pulse.Render(); result.OffsetAllCommandsByTime(startTime); _elementData.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 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; } }
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); }
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); }
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); }
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); }