7
7
#include " ExtrapolationType.h"
8
8
#include " InterpolationAnimatedNode.h"
9
9
#include " NativeAnimatedNodeManager.h"
10
+ #include " Utils/ValueUtils.h"
10
11
11
12
namespace Microsoft ::ReactNative {
13
+
14
+ inline int32_t ColorToInt (winrt::Windows::UI::Color color) {
15
+ return static_cast <uint8_t >(color.A ) << 24 | static_cast <uint8_t >(color.R ) << 16 |
16
+ static_cast <uint8_t >(color.G ) << 8 | static_cast <uint8_t >(color.B );
17
+ }
18
+
19
+ inline uint8_t ScaleByte (uint8_t min, uint8_t max, double ratio) {
20
+ const auto scaledValue = min + (max - min) * ratio;
21
+ const auto clampedValue = std::clamp (static_cast <uint32_t >(std::round (scaledValue)), 0u , 255u );
22
+ return static_cast <uint8_t >(clampedValue);
23
+ }
24
+
12
25
InterpolationAnimatedNode::InterpolationAnimatedNode (
13
26
int64_t tag,
14
27
const winrt::Microsoft::ReactNative::JSValueObject &config,
@@ -17,8 +30,18 @@ InterpolationAnimatedNode::InterpolationAnimatedNode(
17
30
for (const auto &rangeValue : config[s_inputRangeName].AsArray ()) {
18
31
m_inputRanges.push_back (rangeValue.AsDouble ());
19
32
}
20
- for (const auto &rangeValue : config[s_outputRangeName].AsArray ()) {
21
- m_outputRanges.push_back (rangeValue.AsDouble ());
33
+
34
+ const auto isColorOutput = config[s_outputTypeName].AsString () == s_colorOutputType;
35
+ if (!m_useComposition && isColorOutput) {
36
+ m_isColorOutput = true ;
37
+ for (const auto &rangeValue : config[s_outputRangeName].AsArray ()) {
38
+ m_colorOutputRanges.push_back (ColorFrom (rangeValue));
39
+ }
40
+ } else {
41
+ assert (!isColorOutput && " Color interpolation not supported" );
42
+ for (const auto &rangeValue : config[s_outputRangeName].AsArray ()) {
43
+ m_defaultOutputRanges.push_back (rangeValue.AsDouble ());
44
+ }
22
45
}
23
46
24
47
m_extrapolateLeft = config[s_extrapolateLeftName].AsString ();
@@ -33,7 +56,11 @@ void InterpolationAnimatedNode::Update() {
33
56
34
57
if (const auto manager = m_manager.lock ()) {
35
58
if (const auto node = manager->GetValueAnimatedNode (m_parentTag)) {
36
- RawValue (InterpolateValue (node->Value ()));
59
+ if (m_isColorOutput) {
60
+ RawValue (InterpolateColor (node->Value ()));
61
+ } else {
62
+ RawValue (InterpolateValue (node->Value ()));
63
+ }
37
64
}
38
65
}
39
66
}
@@ -95,8 +122,9 @@ comp::ExpressionAnimation InterpolationAnimatedNode::CreateExpressionAnimation(
95
122
for (size_t i = 0 ; i < m_inputRanges.size (); i++) {
96
123
animation.SetScalarParameter (s_inputName.data () + std::to_wstring (i), static_cast <float >(m_inputRanges[i]));
97
124
}
98
- for (size_t i = 0 ; i < m_outputRanges.size (); i++) {
99
- animation.SetScalarParameter (s_outputName.data () + std::to_wstring (i), static_cast <float >(m_outputRanges[i]));
125
+ for (size_t i = 0 ; i < m_defaultOutputRanges.size (); i++) {
126
+ animation.SetScalarParameter (
127
+ s_outputName.data () + std::to_wstring (i), static_cast <float >(m_defaultOutputRanges[i]));
100
128
}
101
129
return animation;
102
130
}
@@ -173,7 +201,7 @@ winrt::hstring InterpolationAnimatedNode::GetRightExpression(
173
201
const winrt::hstring &value,
174
202
const winrt::hstring &rightInterpolateExpression) {
175
203
const auto lastInput = s_inputName.data () + std::to_wstring (m_inputRanges.size () - 1 );
176
- const auto lastOutput = s_outputName.data () + std::to_wstring (m_outputRanges .size () - 1 );
204
+ const auto lastOutput = s_outputName.data () + std::to_wstring (m_defaultOutputRanges .size () - 1 );
177
205
switch (ExtrapolationTypeFromString (m_extrapolateRight)) {
178
206
case ExtrapolationType::Clamp:
179
207
return value + L" > " + lastInput + L" ? " + lastOutput + L" : " ;
@@ -200,10 +228,49 @@ double InterpolationAnimatedNode::InterpolateValue(double value) {
200
228
value,
201
229
m_inputRanges[index ],
202
230
m_inputRanges[index + 1 ],
203
- m_outputRanges [index ],
204
- m_outputRanges [index + 1 ],
231
+ m_defaultOutputRanges [index ],
232
+ m_defaultOutputRanges [index + 1 ],
205
233
m_extrapolateLeft,
206
234
m_extrapolateRight);
207
235
}
208
236
237
+ double InterpolationAnimatedNode::InterpolateColor (double value) {
238
+ // Compute range index
239
+ size_t index = 1 ;
240
+ for (; index < m_inputRanges.size () - 1 ; ++index ) {
241
+ if (m_inputRanges[index ] >= value) {
242
+ break ;
243
+ }
244
+ }
245
+ index --;
246
+
247
+ double result;
248
+ const auto outputMin = m_colorOutputRanges[index ];
249
+ const auto outputMax = m_colorOutputRanges[index + 1 ];
250
+ const auto outputMinInt = ColorToInt (outputMin);
251
+ const auto outputMaxInt = ColorToInt (outputMax);
252
+ if (outputMin == outputMax) {
253
+ memcpy (&result, &outputMinInt, sizeof (int32_t ));
254
+ return result;
255
+ }
256
+
257
+ const auto inputMin = m_inputRanges[index ];
258
+ const auto inputMax = m_inputRanges[index + 1 ];
259
+ if (inputMin == inputMax) {
260
+ if (value <= inputMin) {
261
+ memcpy (&result, &outputMinInt, sizeof (int32_t ));
262
+ } else {
263
+ memcpy (&result, &outputMaxInt, sizeof (int32_t ));
264
+ }
265
+ return result;
266
+ }
267
+
268
+ const auto ratio = (value - inputMin) / (inputMax - inputMin);
269
+ const auto interpolatedColor = ScaleByte (outputMin.A , outputMax.A , ratio) << 24 |
270
+ ScaleByte (outputMin.R , outputMax.R , ratio) << 16 | ScaleByte (outputMin.G , outputMax.G , ratio) << 8 |
271
+ ScaleByte (outputMin.B , outputMax.B , ratio);
272
+ memcpy (&result, &interpolatedColor, sizeof (int32_t ));
273
+ return result;
274
+ }
275
+
209
276
} // namespace Microsoft::ReactNative
0 commit comments