Gradient.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. //
  2. // Gradient.cpp
  3. // cocos2d_libs
  4. //
  5. // Created by 徐俊杰 on 2020/5/22.
  6. //
  7. #include "Gradient.h"
  8. //#include "UnityPrefix.h"
  9. //#include "Runtime/BaseClasses/ObjectDefines.h"
  10. #include "rparticle/Serialize/TransferFunctions/SerializeTransfer.h"
  11. //#include "Runtime/Math/Gradient.h"
  12. NS_RRP_BEGIN
  13. GradientNEW::GradientNEW()
  14. : m_NumColorKeys(2)
  15. , m_NumAlphaKeys(2)
  16. {
  17. m_Keys[0] = m_Keys[1] = ColorRGBA32(0xffffffff);
  18. m_ColorTime[0] = m_AlphaTime[0] = NormalizedToWord(0.0f);
  19. m_ColorTime[1] = m_AlphaTime[1] = NormalizedToWord(1.0f);
  20. for(UInt32 i = 2; i < kGradientMaxNumKeys; i++)
  21. {
  22. m_Keys[i] = ColorRGBA32(0);
  23. m_ColorTime[i] = NormalizedToWord(0.0f);
  24. m_AlphaTime[i] = NormalizedToWord(0.0f);
  25. }
  26. }
  27. GradientNEW::~GradientNEW()
  28. {
  29. }
  30. void GradientNEW::SetKeys (ColorKey* colorKeys, unsigned numColorKeys, AlphaKey* alphaKeys, unsigned numAlphaKeys)
  31. {
  32. SetColorKeys (colorKeys, numColorKeys);
  33. SetAlphaKeys (alphaKeys, numAlphaKeys);
  34. }
  35. void GradientNEW::SwapColorKeys(int i, int j)
  36. {
  37. ColorRGBA32 tmpCol = m_Keys[i];
  38. UInt16 tmpTime = m_ColorTime[i];
  39. m_Keys[i].r = m_Keys[j].r;
  40. m_Keys[i].g = m_Keys[j].g;
  41. m_Keys[i].b = m_Keys[j].b;
  42. m_ColorTime[i] = m_ColorTime[j];
  43. m_Keys[j].r = tmpCol.r;
  44. m_Keys[j].g = tmpCol.g;
  45. m_Keys[j].b = tmpCol.b;
  46. m_ColorTime[j] = tmpTime;
  47. }
  48. void GradientNEW::SwapAlphaKeys(int i, int j)
  49. {
  50. ColorRGBA32 tmpCol = m_Keys[i];
  51. UInt16 tmpTime = m_AlphaTime[i];
  52. m_Keys[i].a = m_Keys[j].a;
  53. m_AlphaTime[i] = m_AlphaTime[j];
  54. m_Keys[j].a = tmpCol.a;
  55. m_AlphaTime[j] = tmpTime;
  56. }
  57. void GradientNEW::SetColorKeys (ColorKey* colorKeys, unsigned numKeys)
  58. {
  59. DebugAssert (numKeys <= kGradientMaxNumKeys);
  60. if (numKeys > kGradientMaxNumKeys)
  61. numKeys = kGradientMaxNumKeys;
  62. for (int i=0; i<numKeys; ++i)
  63. {
  64. const ColorRGBAf& color = colorKeys[i].m_Color;
  65. m_Keys[i].r = NormalizedToByte(color.r);
  66. m_Keys[i].g = NormalizedToByte(color.g);
  67. m_Keys[i].b = NormalizedToByte(color.b);
  68. m_ColorTime[i] = NormalizedToWord(colorKeys[i].m_Time);
  69. }
  70. m_NumColorKeys = numKeys;
  71. // Ensure sorted!
  72. int i = 0;
  73. const int keyCount = m_NumColorKeys;
  74. while ((i + 1) < keyCount)
  75. {
  76. if (m_ColorTime[i] > m_ColorTime[i+1])
  77. {
  78. SwapColorKeys(i, i + 1);
  79. if (i > 0)
  80. i -= 2;
  81. }
  82. i++;
  83. }
  84. ValidateColorKeys();
  85. }
  86. void GradientNEW::SetAlphaKeys (AlphaKey* alphaKeys, unsigned numKeys)
  87. {
  88. DebugAssert (numKeys <= kGradientMaxNumKeys);
  89. if (numKeys > kGradientMaxNumKeys)
  90. numKeys = kGradientMaxNumKeys;
  91. for (int i=0; i<numKeys; ++i)
  92. {
  93. float alpha = alphaKeys[i].m_Alpha;
  94. m_Keys[i].a = NormalizedToByte(alpha);
  95. m_AlphaTime[i] = NormalizedToWord(alphaKeys[i].m_Time);
  96. }
  97. m_NumAlphaKeys = numKeys;
  98. // Ensure sorted!
  99. int i = 0;
  100. const int keyCount = m_NumAlphaKeys;
  101. while ((i + 1) < keyCount)
  102. {
  103. if (m_AlphaTime[i] > m_AlphaTime[i+1])
  104. {
  105. SwapAlphaKeys(i, i + 1);
  106. if (i > 0)
  107. i -= 2;
  108. }
  109. i++;
  110. }
  111. ValidateAlphaKeys();
  112. }
  113. ColorRGBA32 GradientNEW::GetConstantColor () const
  114. {
  115. return m_Keys[0];
  116. }
  117. void GradientNEW::SetConstantColor (ColorRGBA32 color)
  118. {
  119. m_Keys[0] = color;
  120. m_NumAlphaKeys = 1;
  121. m_NumColorKeys = 1;
  122. }
  123. void GradientNEW::ValidateColorKeys()
  124. {
  125. // Make sure there is a minimum of 2 keys
  126. if(m_NumColorKeys < 2)
  127. {
  128. m_NumColorKeys = 2;
  129. for(int rgb = 0; rgb < 3; rgb++)
  130. m_Keys[1][rgb] = m_Keys[0][rgb];
  131. m_ColorTime[0] = NormalizedToWord(0.0f);
  132. m_ColorTime[1] = NormalizedToWord(1.0f);
  133. }
  134. }
  135. void GradientNEW::ValidateAlphaKeys()
  136. {
  137. // Make sure there is a minimum of 2 keys
  138. if(m_NumAlphaKeys < 2)
  139. {
  140. m_NumAlphaKeys = 2;
  141. m_Keys[1].a = m_Keys[0].a;
  142. m_AlphaTime[0] = NormalizedToWord(0.0f);
  143. m_AlphaTime[1] = NormalizedToWord(1.0f);
  144. }
  145. }
  146. void GradientNEW::InitializeOptimized(OptimizedGradient& gradient)
  147. {
  148. // Copy all time values
  149. for(int i = 0; i < m_NumColorKeys; ++i)
  150. gradient.times[i] = m_ColorTime[i];
  151. for(int i = 0, i2 = m_NumColorKeys; i < m_NumAlphaKeys; ++i, ++i2)
  152. gradient.times[i2] = m_AlphaTime[i];
  153. // Remove duplicates
  154. int keyCount = m_NumColorKeys + m_NumAlphaKeys;
  155. for(int i = 0; i < keyCount-1; ++i)
  156. {
  157. for(int j = i+1; j < keyCount; )
  158. {
  159. if(gradient.times[i] == gradient.times[j])
  160. {
  161. std::swap(gradient.times[j], gradient.times[keyCount-1]);
  162. keyCount--;
  163. continue;
  164. }
  165. ++j;
  166. }
  167. }
  168. // Sort
  169. int i = 0;
  170. while ((i + 1) < keyCount)
  171. {
  172. if (gradient.times[i] > gradient.times[i+1])
  173. {
  174. std::swap(gradient.times[i], gradient.times[i+1]);
  175. if (i > 0)
  176. i -= 2;
  177. }
  178. i++;
  179. }
  180. for(int i = 0; i < keyCount; ++i)
  181. gradient.colors[i] = Evaluate(WordToNormalized(gradient.times[i]));
  182. gradient.keyCount = keyCount;
  183. for(int i = 1; i < keyCount; ++i)
  184. gradient.rcp[i] = ((((1<<24)) / std::max<UInt32>(gradient.times[i] - gradient.times[i-1], 1)))+1;
  185. }
  186. template<class TransferFunction>
  187. void GradientNEW::Transfer (TransferFunction& transfer)
  188. {
  189. AssertIf (kGradientMaxNumKeys > 9);
  190. const char* kKeyNames [kGradientMaxNumKeys] = { "key0", "key1", "key2", "key3", "key4", "key5", "key6", "key7", };
  191. for(UInt32 i = 0; i < kGradientMaxNumKeys; i++)
  192. transfer.Transfer(m_Keys[i], kKeyNames[i]);//, kHideInEditorMask);
  193. const char* kColorTimeNames [kGradientMaxNumKeys] = { "ctime0", "ctime1", "ctime2", "ctime3", "ctime4", "ctime5", "ctime6", "ctime7", };
  194. for(UInt32 i = 0; i < kGradientMaxNumKeys; i++)
  195. transfer.Transfer(m_ColorTime[i], kColorTimeNames[i]);//, kHideInEditorMask);
  196. const char* kAlphaTimeNames [kGradientMaxNumKeys] = { "atime0", "atime1", "atime2", "atime3", "atime4", "atime5", "atime6", "atime7", };
  197. for(UInt32 i = 0; i < kGradientMaxNumKeys; i++)
  198. transfer.Transfer(m_AlphaTime[i], kAlphaTimeNames[i]);//, kHideInEditorMask);
  199. transfer.Transfer (m_NumColorKeys, "m_NumColorKeys");//, kHideInEditorMask);
  200. transfer.Transfer (m_NumAlphaKeys, "m_NumAlphaKeys");//, kHideInEditorMask);
  201. transfer.Align();
  202. if(transfer.IsReading())
  203. {
  204. ValidateColorKeys();
  205. ValidateAlphaKeys();
  206. }
  207. }
  208. INSTANTIATE_TEMPLATE_TRANSFER(GradientNEW)
  209. #if ENABLE_UNIT_TESTS
  210. #include "External/UnitTest++/src/UnitTest++.h"
  211. bool CompareColors(ColorRGBA32 c0, ColorRGBA32 c1, int tolerance)
  212. {
  213. if(Abs(c0.r-c1.r) > tolerance)
  214. return false;
  215. if(Abs(c0.g-c1.g) > tolerance)
  216. return false;
  217. if(Abs(c0.b-c1.b) > tolerance)
  218. return false;
  219. if(Abs(c0.a-c1.a) > tolerance)
  220. return false;
  221. return true;
  222. }
  223. SUITE (GradientTests)
  224. {
  225. TEST (GradientTests_GradientEvaluate)
  226. {
  227. // Set up rainbow gradient
  228. GradientNEW gradient;
  229. gradient.SetNumColorKeys(5);
  230. gradient.SetNumAlphaKeys(3);
  231. gradient.GetKey(0) = ColorRGBA32(0xff, 0x00, 0x00, 0xff);
  232. gradient.GetKey(1) = ColorRGBA32(0xf8, 0xff, 0x00, 0x00);
  233. gradient.GetKey(2) = ColorRGBA32(0x00, 0xff, 0x49, 0xff);
  234. gradient.GetKey(3) = ColorRGBA32(0x22, 0x00, 0xff, 0x00);
  235. gradient.GetKey(4) = ColorRGBA32(0xff, 0x00, 0xe6, 0x00);
  236. gradient.GetColorTime(0) = 0x0000;
  237. gradient.GetColorTime(1) = 0x40c1;
  238. gradient.GetColorTime(2) = 0x9212;
  239. gradient.GetColorTime(3) = 0xce4e;
  240. gradient.GetColorTime(4) = 0xffff;
  241. gradient.GetAlphaTime(0) = 0x0000;
  242. gradient.GetAlphaTime(1) = 0x8000;
  243. gradient.GetAlphaTime(2) = 0xffff;
  244. CHECK_EQUAL(ColorRGBA32(0xff, 0x00, 0x00, 0xff) == gradient.Evaluate(0.0f), true);
  245. CHECK_EQUAL(ColorRGBA32(0xfd, 0x31, 0x00, 0xe6) == gradient.Evaluate(0.05f), true);
  246. CHECK_EQUAL(ColorRGBA32(0xfa, 0x96, 0x00, 0xb3) == gradient.Evaluate(0.15f), true);
  247. CHECK_EQUAL(ColorRGBA32(0xf8, 0xfc, 0x00, 0x7f) == gradient.Evaluate(0.25f), true);
  248. CHECK_EQUAL(ColorRGBA32(0xac, 0xff, 0x16, 0x4c) == gradient.Evaluate(0.35f), true);
  249. CHECK_EQUAL(ColorRGBA32(0x5e, 0xff, 0x2d, 0x19) == gradient.Evaluate(0.45f), true);
  250. CHECK_EQUAL(ColorRGBA32(0x10, 0xff, 0x44, 0x18) == gradient.Evaluate(0.55f), true);
  251. CHECK_EQUAL(ColorRGBA32(0x0b, 0xa9, 0x86, 0x4b) == gradient.Evaluate(0.65f), true);
  252. CHECK_EQUAL(ColorRGBA32(0x19, 0x3c, 0xd3, 0x7e) == gradient.Evaluate(0.75f), true);
  253. CHECK_EQUAL(ColorRGBA32(0x54, 0x00, 0xf9, 0xb2) == gradient.Evaluate(0.85f), true);
  254. CHECK_EQUAL(ColorRGBA32(0xc6, 0x00, 0xec, 0xe5) == gradient.Evaluate(0.95f), true);
  255. CHECK_EQUAL(ColorRGBA32(0xff, 0x00, 0xe6, 0xff) == gradient.Evaluate(1.0f), true);
  256. OptimizedGradient optGradient;
  257. gradient.InitializeOptimized(optGradient);
  258. #if UNITY_LINUX
  259. #warning Investigate/fix GradientEvaluateTest!
  260. #else
  261. // Being off by 1LSB is okay... (due to rounding)
  262. for(float time = 0.0f; time <= 1.0f; time += 0.02f)
  263. CHECK_EQUAL(CompareColors(optGradient.Evaluate(time), gradient.Evaluate(time), 1), true);
  264. // ... but require exactness precicely at key times
  265. for(int i = 0; i < 5; i++)
  266. {
  267. float time = WordToNormalized(gradient.GetColorTime(i));
  268. CHECK_EQUAL(CompareColors(optGradient.Evaluate(time), gradient.Evaluate(time), 0), true);
  269. }
  270. for(int i = 0; i < 3; i++)
  271. {
  272. float time = WordToNormalized(gradient.GetAlphaTime(i));
  273. CHECK_EQUAL(CompareColors(optGradient.Evaluate(time), gradient.Evaluate(time), 0), true);
  274. }
  275. #endif
  276. }
  277. }
  278. #endif
  279. NS_RRP_END