1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #include "Image/BsColorGradient.h" |
4 | #include "Private/RTTI/BsColorGradientRTTI.h" |
5 | #include "Debug/BsDebug.h" |
6 | #include "Utility/BsBitwise.h" |
7 | |
8 | namespace bs |
9 | { |
10 | ColorGradient::ColorGradient(const Color& color) |
11 | { |
12 | setConstant(color); |
13 | } |
14 | |
15 | ColorGradient::ColorGradient(const Vector<ColorGradientKey>& keys) |
16 | { |
17 | setKeys(keys); |
18 | } |
19 | |
20 | RGBA ColorGradient::evaluate(float t) const |
21 | { |
22 | if(mNumKeys == 0) |
23 | return 0; |
24 | |
25 | if(mNumKeys == 1) |
26 | return mColors[0]; |
27 | |
28 | if(mDuration > 0.0f) |
29 | t = t / mDuration; |
30 | |
31 | const uint32_t time = Bitwise::unormToUint<16>(Math::clamp01(t)); |
32 | |
33 | if(time < mTimes[0]) |
34 | return mColors[0]; |
35 | |
36 | // Note: Add a version of evaluate that supports caching? |
37 | for(UINT32 i = 1; i < mNumKeys; i++) |
38 | { |
39 | const uint32_t curKeyTime = mTimes[i]; |
40 | if(time > curKeyTime) |
41 | continue; |
42 | |
43 | const uint32_t prevKeyTime = mTimes[i - 1]; |
44 | const uint32_t fracColor = Bitwise::invLerpWord(prevKeyTime, curKeyTime, time) >> 8; |
45 | return Color::lerp(fracColor, mColors[i - 1], mColors[i]); |
46 | } |
47 | |
48 | return mColors[mNumKeys - 1]; |
49 | } |
50 | |
51 | void ColorGradient::setKeys(const Vector<ColorGradientKey>& keys, float duration) |
52 | { |
53 | #if BS_DEBUG_MODE |
54 | // Ensure keys are sorted |
55 | if(!keys.empty()) |
56 | { |
57 | float time = keys[0].time; |
58 | for (UINT32 i = 1; i < (UINT32)keys.size(); i++) |
59 | { |
60 | assert(keys[i].time >= time); |
61 | time = keys[i].time; |
62 | } |
63 | } |
64 | #endif |
65 | |
66 | if(keys.size() > MAX_KEYS) |
67 | { |
68 | LOGWRN("Number of keys in ColorGradient exceeds the support number (" + |
69 | toString(MAX_KEYS) + "). Keys will be ignored." ); |
70 | } |
71 | |
72 | mDuration = duration; |
73 | mNumKeys = 0; |
74 | |
75 | for(auto& key : keys) |
76 | { |
77 | if(mNumKeys >= MAX_KEYS) |
78 | break; |
79 | |
80 | mColors[mNumKeys] = key.color.getAsRGBA(); |
81 | mTimes[mNumKeys] = Bitwise::unormToUint<16>(Math::clamp01(key.time)); |
82 | |
83 | mNumKeys++; |
84 | } |
85 | } |
86 | |
87 | Vector<ColorGradientKey> ColorGradient::getKeys() const |
88 | { |
89 | Vector<ColorGradientKey> output(mNumKeys); |
90 | for(UINT32 i = 0; i < mNumKeys; i++) |
91 | { |
92 | output[i].color = Color::fromRGBA(mColors[i]); |
93 | output[i].time = Bitwise::uintToUnorm<16>(mTimes[i]); |
94 | } |
95 | |
96 | return output; |
97 | } |
98 | |
99 | ColorGradientKey ColorGradient::getKey(UINT32 idx) const |
100 | { |
101 | if(idx >= mNumKeys) |
102 | return ColorGradientKey(Color::Black, 0.0f); |
103 | |
104 | return ColorGradientKey(Color::fromRGBA(mColors[idx]), Bitwise::uintToUnorm<16>(mTimes[idx])); |
105 | } |
106 | |
107 | void ColorGradient::setConstant(const Color& color) |
108 | { |
109 | mColors[0] = color.getAsRGBA(); |
110 | mTimes[0] = 0; |
111 | mNumKeys = 1; |
112 | mDuration = 0.0f; |
113 | } |
114 | |
115 | std::pair<float, float> ColorGradient::getTimeRange() const |
116 | { |
117 | if(mNumKeys == 0) |
118 | return std::make_pair(0.0f, 0.0f); |
119 | |
120 | if(mNumKeys == 1) |
121 | { |
122 | float time = Bitwise::uintToUnorm<16>(mTimes[0]); |
123 | return std::make_pair(time, time); |
124 | } |
125 | |
126 | return std::make_pair( |
127 | Bitwise::uintToUnorm<16>(mTimes[0]), |
128 | Bitwise::uintToUnorm<16>(mTimes[mNumKeys - 1]) |
129 | ); |
130 | } |
131 | |
132 | bool ColorGradient::operator== (const ColorGradient& rhs) const |
133 | { |
134 | if (mNumKeys != rhs.mNumKeys || mDuration != rhs.mDuration) |
135 | return false; |
136 | |
137 | for (uint32_t i = 0; i < mNumKeys; i++) |
138 | { |
139 | if (mColors[i] != rhs.mColors[i] || mTimes[i] != rhs.mTimes[i]) |
140 | return false; |
141 | } |
142 | |
143 | return true; |
144 | } |
145 | } |
146 | |