ImageUtils.cpp 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118
  1. #include "ImageUtils.h"
  2. #include "ImageData.h"
  3. #include "Common.h"
  4. #include "util/PerfTimer.h"
  5. USING_NS_BF;
  6. const int DISSOLVE_SIZE = 6679;
  7. static uint8 gDissolveTable[DISSOLVE_SIZE];
  8. static bool gDissolveInitialized = false;
  9. static int gDissolveIdx = 0;
  10. static int gSqrtTable[256];
  11. struct WideColor
  12. {
  13. int r;
  14. int g;
  15. int b;
  16. int a;
  17. };
  18. static inline float clamp(float val, float min, float max)
  19. {
  20. return (val <= min) ? min : (val >= max) ? max : val;
  21. }
  22. static inline int clamp(int val, int min, int max)
  23. {
  24. return (val <= min) ? min : (val >= max) ? max : val;
  25. }
  26. #define Blend_Apply(Blend_Channel) \
  27. aBlendedColor.r = Blend_Channel((int) aDestColor->r, (int) aSrcColor->r); \
  28. aBlendedColor.g = Blend_Channel((int) aDestColor->g, (int) aSrcColor->g); \
  29. aBlendedColor.b = Blend_Channel((int) aDestColor->b, (int) aSrcColor->b);
  30. inline PackedColor SetSat(PackedColor color, int satVal)
  31. {
  32. #define SetSatComponents(minComp, midComp, maxComp) \
  33. { \
  34. midComp -= minComp; \
  35. maxComp -= minComp; \
  36. minComp = 0; \
  37. if (maxComp > 0) \
  38. { \
  39. midComp = midComp*satVal/maxComp; \
  40. maxComp = satVal; \
  41. } \
  42. }
  43. if (color.r <= color.g)
  44. {
  45. if (color.g <= color.b)
  46. SetSatComponents(color.r, color.g, color.b)
  47. else if (color.r < color.b)
  48. SetSatComponents(color.r, color.b, color.g)
  49. else
  50. SetSatComponents(color.b, color.r, color.g);
  51. }
  52. else
  53. {
  54. if (color.r <= color.b)
  55. SetSatComponents(color.g, color.r, color.b)
  56. else if (color.g < color.b)
  57. SetSatComponents(color.g, color.b, color.r)
  58. else
  59. SetSatComponents(color.b, color.g, color.r);
  60. }
  61. return color;
  62. }
  63. #define max3( x, y, z ) ( std::max((x), std::max((y), (z))) )
  64. #define min3( x, y, z ) ( std::min((x), std::min((y), (z))) )
  65. #define Sat(C) ( (max3(((C).r), ((C).g), ((C).b)) - min3(((C).r), ((C).g), ((C).b))) )
  66. #define Lum(C) ( ((((C).r) * 300) + (((C).g) * 586) + (((C).b) * 113)) / 1000 )
  67. inline PackedColor SetLum(PackedColor color, int lum)
  68. {
  69. //int lum_cl = luminance(color);
  70. int d = lum - Lum(color);
  71. WideColor color_cl = {color.r + d, color.g + d, color.b + d, color.a};
  72. int aLum = Lum(color_cl);
  73. int mini = min3(color_cl.r, color_cl.g, color_cl.b);
  74. int maxi = max3(color_cl.r, color_cl.g, color_cl.b);
  75. if (mini < 0)
  76. {
  77. color.r = (int) aLum + (color_cl.r - aLum)*aLum/std::max(aLum - mini, 1);
  78. color.g = (int) aLum + (color_cl.g - aLum)*aLum/std::max(aLum - mini, 1);
  79. color.b = (int) aLum + (color_cl.b - aLum)*aLum/std::max(aLum - mini, 1);
  80. }
  81. else if (maxi > 255)
  82. {
  83. color.r = aLum + (color_cl.r - aLum)*(255 - aLum)/std::max(maxi - aLum, 1);
  84. color.g = aLum + (color_cl.g - aLum)*(255 - aLum)/std::max(maxi - aLum, 1);
  85. color.b = aLum + (color_cl.b - aLum)*(255 - aLum)/std::max(maxi - aLum, 1);
  86. }
  87. else
  88. {
  89. color.r = color_cl.r;
  90. color.g = color_cl.g;
  91. color.b = color_cl.b;
  92. }
  93. return color;
  94. }
  95. inline int ClampedOffset(int cur, int to, int maxDelta)
  96. {
  97. int delta = abs(to - cur);
  98. if (abs(delta) < maxDelta)
  99. return to;
  100. if (cur < to)
  101. return cur + maxDelta;
  102. return cur - maxDelta;
  103. }
  104. ImageData* Beefy::CreateResizedImageUnion(ImageData* src, int x, int y, int width, int height)
  105. {
  106. int minX = std::min(src->mX, x);
  107. int minY = std::min(src->mY, y);
  108. int maxX = std::max(src->mX + src->mWidth, x + width);
  109. int maxY = std::max(src->mY + src->mHeight, y + height);
  110. /*if ((src->mX == minX) && (src->mY == minY) && (src->mWidth == maxX - minX) && (src->mHeight == maxY - minY))
  111. return src;*/
  112. ImageData* imageData = new ImageData();
  113. imageData->CreateNew(maxX - minX, maxY - minY);
  114. imageData->mX = minX;
  115. imageData->mY = minY;
  116. for (int y = src->mY; y < src->mY + src->mHeight; y++)
  117. {
  118. for (int x = src->mX; x < src->mX + src->mWidth; x++)
  119. {
  120. PackedColor* aDest = (PackedColor*) &imageData->mBits[(x - imageData->mX) + (y - imageData->mY)*imageData->mWidth];
  121. PackedColor* aSrc = (PackedColor*) &src->mBits[(x - src->mX) + (y - src->mY)*src->mWidth];
  122. *aDest = *aSrc;
  123. }
  124. }
  125. return imageData;
  126. }
  127. ImageData* Beefy::CreateEmptyResizedImageUnion(ImageData* src, int x, int y, int width, int height)
  128. {
  129. ImageData* imageData = new ImageData();
  130. if (src == NULL)
  131. {
  132. imageData->CreateNew(x, y, width, height);
  133. return imageData;
  134. }
  135. int minX = std::min(src->mX, x);
  136. int minY = std::min(src->mY, y);
  137. int maxX = std::max(src->mX + src->mWidth, x + width);
  138. int maxY = std::max(src->mY + src->mHeight, y + height);
  139. imageData->CreateNew(maxX - minX, maxY - minY);
  140. imageData->mX = minX;
  141. imageData->mY = minY;
  142. return imageData;
  143. }
  144. void Beefy::CrossfadeImage(ImageData* origImage, ImageData* newImage, float opacity)
  145. {
  146. AutoPerf gPerf("Beefy::CrossfadeImage");
  147. int a = (int) (opacity * 255 + 0.5f);
  148. int oma = 255 - a;
  149. if (a == 255) // No crossfade needed
  150. return;
  151. if (origImage == NULL)
  152. {
  153. for (int y = newImage->mY; y < newImage->mY + newImage->mHeight; y++)
  154. {
  155. for (int x = newImage->mX; x < newImage->mX + newImage->mWidth; x++)
  156. {
  157. PackedColor* aDest = (PackedColor*) &newImage->mBits[(x - newImage->mX) + (y - newImage->mY)*newImage->mWidth];
  158. aDest->a = (aDest->a * a) / 255;
  159. aDest++;
  160. }
  161. }
  162. }
  163. else
  164. {
  165. for (int x = newImage->mX; x < newImage->mX + newImage->mWidth; x++)
  166. {
  167. // Top
  168. for (int y = newImage->mY; y < origImage->mY; y++)
  169. {
  170. PackedColor* aDest = (PackedColor*) &newImage->mBits[(x - newImage->mX) + (y - newImage->mY)*newImage->mWidth];
  171. aDest->a = (aDest->a * a) / 255;
  172. aDest++;
  173. }
  174. // Bottom
  175. for (int y = origImage->mY + origImage->mHeight; y < newImage->mY + newImage->mHeight; y++)
  176. {
  177. PackedColor* aDest = (PackedColor*) &newImage->mBits[(x - newImage->mX) + (y - newImage->mY)*newImage->mWidth];
  178. aDest->a = (aDest->a * a) / 255;
  179. aDest++;
  180. }
  181. }
  182. // Crash seems to be here:
  183. for (int y = origImage->mY; y < origImage->mY + origImage->mHeight; y++)
  184. {
  185. // Left
  186. for (int x = newImage->mX; x < origImage->mX; x++)
  187. {
  188. PackedColor* aDest = (PackedColor*) &newImage->mBits[(x - newImage->mX) + (y - newImage->mY)*newImage->mWidth];
  189. aDest->a = (aDest->a * a) / 255;
  190. aDest++;
  191. }
  192. // Right
  193. for (int x = origImage->mX + origImage->mWidth; x < newImage->mX + newImage->mWidth; x++)
  194. {
  195. PackedColor* aDest = (PackedColor*) &newImage->mBits[(x - newImage->mX) + (y - newImage->mY)*newImage->mWidth];
  196. aDest->a = (aDest->a * a) / 255;
  197. aDest++;
  198. }
  199. }
  200. for (int y = origImage->mY; y < origImage->mY + origImage->mHeight; y++)
  201. {
  202. for (int x = origImage->mX; x < origImage->mX + origImage->mWidth; x++)
  203. {
  204. PackedColor* aDest = (PackedColor*) &newImage->mBits[(x - newImage->mX) + (y - newImage->mY)*newImage->mWidth];
  205. PackedColor* aSrc = (PackedColor*) &origImage->mBits[(x - origImage->mX) + (y - origImage->mY)*origImage->mWidth];
  206. int newDestAlpha = ((aDest->a * a) + (aSrc->a * oma)) / 255;
  207. if (newDestAlpha != 0)
  208. {
  209. int ca = (255 * a * aDest->a) / (aDest->a * a + aSrc->a * oma);
  210. int coma = 255 - ca;
  211. aDest->a = newDestAlpha;
  212. aDest->r = ((aDest->r * ca) + (aSrc->r * coma)) / 255;
  213. aDest->g = ((aDest->g * ca) + (aSrc->g * coma)) / 255;
  214. aDest->b = ((aDest->b * ca) + (aSrc->b * coma)) / 255;
  215. }
  216. aSrc++;
  217. aDest++;
  218. }
  219. }
  220. }
  221. }
  222. // aSrcColor, aDestColor, aBlendAlpha
  223. // doReverseBlend, doFullBlend, doAltBlend, normal blend
  224. class BlendGetColor_Normal
  225. {
  226. public:
  227. PackedColor operator()(PackedColor* srcColor, PackedColor* destColor, int srcAlpha, int blendAlpha)
  228. {
  229. PackedColor aBlendedColor = *srcColor;
  230. aBlendedColor.a = srcAlpha;
  231. return aBlendedColor;
  232. }
  233. };
  234. class BlendMix_Normal
  235. {
  236. public:
  237. void operator()(PackedColor* srcColor, PackedColor* destColor, PackedColor blendedColor, int srcAlpha, int blendAlpha)
  238. {
  239. int newDestAlpha = 255;
  240. int a = blendedColor.a;
  241. if (destColor->a != 255)
  242. newDestAlpha = destColor->a + ((255 - destColor->a) * blendedColor.a) / 255;
  243. if (newDestAlpha != 0)
  244. {
  245. a = 255 * blendedColor.a / newDestAlpha;
  246. int ba = destColor->a;
  247. int boma = 255 - destColor->a;
  248. blendedColor.r = ((blendedColor.r * ba) + (srcColor->r * boma)) / 255;
  249. blendedColor.g = ((blendedColor.g * ba) + (srcColor->g * boma)) / 255;
  250. blendedColor.b = ((blendedColor.b * ba) + (srcColor->b * boma)) / 255;
  251. }
  252. int oma = 255 - a;
  253. destColor->a = newDestAlpha;
  254. destColor->r = ((blendedColor.r * a) + (destColor->r * oma)) / 255;
  255. destColor->g = ((blendedColor.g * a) + (destColor->g * oma)) / 255;
  256. destColor->b = ((blendedColor.b * a) + (destColor->b * oma)) / 255;
  257. }
  258. };
  259. template <class GetColorFunctor, class MixFunctor>
  260. static void BlendImage_Fast_T(ImageData* dest, ImageData* src, int destX, int destY, float alpha, int mixType, bool fullAlpha)
  261. {
  262. AutoPerf gPerf("Beefy::BlendImage");
  263. BF_ASSERT(destX >= 0);
  264. BF_ASSERT(destY >= 0);
  265. BF_ASSERT(destX + src->mWidth <= dest->mWidth);
  266. BF_ASSERT(destY + src->mHeight <= dest->mHeight);
  267. if (!gDissolveInitialized)
  268. {
  269. for (int i = 0; i < DISSOLVE_SIZE; i++)
  270. gDissolveTable[i] = rand() % 1023;
  271. gDissolveInitialized = true;
  272. for (int i = 0; i < 256; i++)
  273. gSqrtTable[i] = (int) (sqrt(i / 255.0f) * 255.0f + 0.5f);
  274. }
  275. int aBlendAlpha = (int) (255 * alpha);
  276. for (int y = 0; y < src->mHeight; y++)
  277. {
  278. PackedColor* aSrcColor = (PackedColor*) (src->mBits + (y * src->mWidth));
  279. PackedColor* aDestColor = (PackedColor*) (dest->mBits + destX + (y + destY) * dest->mWidth);
  280. for (int x = 0; x < src->mWidth; x++)
  281. {
  282. int aSrcAlpha = (int) (aSrcColor->a * alpha + 0.5f);
  283. if (fullAlpha)
  284. aSrcAlpha = (int) (alpha * 255 + 0.5f);
  285. PackedColor aBlendedColor = GetColorFunctor()(aSrcColor, aDestColor, aSrcAlpha, aBlendAlpha);
  286. MixFunctor()(aSrcColor, aDestColor, aBlendedColor, aSrcAlpha, aBlendAlpha);
  287. aDestColor++;
  288. aSrcColor++;
  289. }
  290. }
  291. }
  292. static void BlendImage_Fast(ImageData* dest, ImageData* src, int destX, int destY, float alpha, int mixType, bool fullAlpha)
  293. {
  294. BlendImage_Fast_T<BlendGetColor_Normal, BlendMix_Normal>(dest, src, destX, destY, alpha, mixType, fullAlpha);
  295. }
  296. void Beefy::BlendImage(ImageData* dest, ImageData* src, int destX, int destY, float alpha, int mixType, bool fullAlpha)
  297. {
  298. /*BlendImage_Fast(dest, src, destX, destY, alpha, mixType, fullAlpha);
  299. return;*/
  300. AutoPerf gPerf("Beefy::BlendImage");
  301. BF_ASSERT(destX >= 0);
  302. BF_ASSERT(destY >= 0);
  303. BF_ASSERT(destX + src->mWidth <= dest->mWidth);
  304. BF_ASSERT(destY + src->mHeight <= dest->mHeight);
  305. if (!gDissolveInitialized)
  306. {
  307. for (int i = 0; i < DISSOLVE_SIZE; i++)
  308. gDissolveTable[i] = rand() % 1023;
  309. gDissolveInitialized = true;
  310. for (int i = 0; i < 256; i++)
  311. gSqrtTable[i] = (int) (sqrt(i / 255.0f) * 255.0f + 0.5f);
  312. }
  313. int aBlendAlpha = (int) (255 * alpha);
  314. for (int y = 0; y < src->mHeight; y++)
  315. {
  316. PackedColor* aSrcColor = (PackedColor*) (src->mBits + (y * src->mWidth));
  317. PackedColor* aDestColor = (PackedColor*) (dest->mBits + destX + (y + destY) * dest->mWidth);
  318. for (int x = 0; x < src->mWidth; x++)
  319. {
  320. int aSrcAlpha = (int) (aSrcColor->a * alpha + 0.5f);
  321. if (fullAlpha)
  322. aSrcAlpha = (int) (alpha * 255 + 0.5f);
  323. PackedColor aBlendedColor = *aSrcColor;
  324. aBlendedColor.a = aSrcAlpha;
  325. bool doReverseBlend = false;
  326. bool doAltBlend = false;
  327. bool doFullBlend = false;
  328. if ((mixType == 'Nrml') || (mixType == 'norm')) // Normal
  329. {
  330. }
  331. else if ((mixType == 'Lghn') || (mixType == 'lite')) // Lighten
  332. {
  333. aBlendedColor.r = std::max((int) aSrcColor->r, (int) aDestColor->r);
  334. aBlendedColor.g = std::max((int) aSrcColor->g, (int) aDestColor->g);
  335. aBlendedColor.b = std::max((int) aSrcColor->b, (int) aDestColor->b);
  336. }
  337. else if ((mixType == 'Drkn') || (mixType == 'dark')) // Darken
  338. {
  339. aBlendedColor.r = std::min((int) aSrcColor->r, (int) aDestColor->r);
  340. aBlendedColor.g = std::min((int) aSrcColor->g, (int) aDestColor->g);
  341. aBlendedColor.b = std::min((int) aSrcColor->b, (int) aDestColor->b);
  342. }
  343. else if (mixType == 'blen')
  344. {
  345. aBlendedColor.r = std::max(0, (int) aDestColor->r - (int) aSrcColor->r);
  346. aBlendedColor.g = std::max(0, (int) aDestColor->g - (int) aSrcColor->g);
  347. aBlendedColor.b = std::max(0, (int) aDestColor->b - (int) aSrcColor->b);
  348. }
  349. else if ((mixType == 'Dslv') || (mixType == 'diss')) // Disolve
  350. {
  351. if ((dest->mX + x == 132) && (dest->mY + y == 19))
  352. {
  353. /*aBlendedColor.a = 255;
  354. aBlendedColor.r = 0;
  355. aBlendedColor.g = 255;
  356. aBlendedColor.b = 0; */
  357. }
  358. int dissolveIdx = ((dest->mX + x) * 179 + (dest->mY + y) * 997) % DISSOLVE_SIZE;
  359. if ((int) (aSrcColor->a * alpha + 0.5f) < gDissolveTable[dissolveIdx])
  360. aBlendedColor.a = 0;
  361. else
  362. aBlendedColor.a = 255;
  363. }
  364. else if ((mixType == 'Mltp') || (mixType == 'mul ')) // Multiply
  365. {
  366. aBlendedColor.r = (int) aDestColor->r * (int) aSrcColor->r / 255;
  367. aBlendedColor.g = (int) aDestColor->g * (int) aSrcColor->g / 255;
  368. aBlendedColor.b = (int) aDestColor->b * (int) aSrcColor->b / 255;
  369. }
  370. else if ((mixType == 'CBrn') || (mixType == 'idiv')) // Color Burn
  371. {
  372. if (mixType == 'CBrn') // Effect
  373. {
  374. int blendVal = (aBlendAlpha * aSrcColor->a / 255);
  375. #define Blend_ColorBurn_Effect(A,B) \
  376. std::max(0, 255 - (((255 - (int) A) << 8 ) / std::max((((B * blendVal) + (255 * (255 - blendVal))) / 255), 1)))
  377. Blend_Apply(Blend_ColorBurn_Effect);
  378. //doFullBlend = true;
  379. }
  380. else // Layer
  381. {
  382. #define Blend_ColorBurn(A,B) \
  383. std::max(0, 255 - (((255 - (int) A) << 8 ) / std::max((((B * aBlendAlpha) + (255 * (255 - aBlendAlpha))) / 255), 1)))
  384. Blend_Apply(Blend_ColorBurn);
  385. doFullBlend = true;
  386. }
  387. }
  388. else if ((mixType == 'lnDg') || (mixType == 'lddg')) // Linear Dodge
  389. {
  390. // Uses alternate blend methdod
  391. }
  392. else if (mixType == 'lbrn') // Linear Burn (Layer)
  393. {
  394. /*int newDestAlpha = aDestColor->a + ((255 - aDestColor->a) * aBlendedColor.a) / 255;
  395. #define Blend_LinearDodge_Layer(A,B) \
  396. 255 - std::min(255, (255 - A) + (255 - B))
  397. Blend_Apply(Blend_LinearDodge_Layer); */
  398. }
  399. else if (mixType == 'lnBn')
  400. {
  401. // Uses alternate blend methdod
  402. }
  403. else if (mixType == 'dkCl') // Darker Color
  404. {
  405. // 299, 587, 144 is "correct"
  406. int intensityDest = (aDestColor->r * 300) + (aDestColor->g * 586) + (aDestColor->b * 113);
  407. int intensitySrc = (aSrcColor->r * 300) + (aSrcColor->g * 586) + (aSrcColor->b * 113);
  408. if (intensityDest <= intensitySrc)
  409. doReverseBlend = true;
  410. }
  411. else if ((mixType == 'ltCl') || (mixType == 'lgCl')) // Lighter Color
  412. {
  413. if ((dest->mX + x == 125) && (dest->mY + y == 299))
  414. {
  415. /*aDestColor->a = 255;
  416. aDestColor->r = 0;
  417. aDestColor->g = 255;
  418. aDestColor->b = 0; */
  419. }
  420. // 299, 587, 144 is "correct"
  421. int intensityDest = (aDestColor->r * 300) + (aDestColor->g * 586) + (aDestColor->b * 113);
  422. int intensitySrc = (aSrcColor->r * 300) + (aSrcColor->g * 586) + (aSrcColor->b * 113);
  423. if (intensityDest >= intensitySrc)
  424. doReverseBlend = true;
  425. }
  426. else if ((mixType == 'Scrn') || (mixType == 'scrn')) // Screen
  427. {
  428. aBlendedColor.r = 255 - ((255 - aDestColor->r) * (255 - aSrcColor->r) / 255);
  429. aBlendedColor.g = 255 - ((255 - aDestColor->g) * (255 - aSrcColor->g) / 255);
  430. aBlendedColor.b = 255 - ((255 - aDestColor->b) * (255 - aSrcColor->b) / 255);
  431. }
  432. else if ((mixType == 'CDdg') || (mixType == 'div ')) // Color Dodge
  433. {
  434. if (mixType == 'CDdg') // Effect
  435. {
  436. int blendVal = (aBlendAlpha * aSrcColor->a / 255);
  437. #define Blend_ColorDodge_Effect(A,B) \
  438. std::min(255, ((((int) A) << 8 ) / std::max((((255 - B) * blendVal) + (255 * (255 - blendVal))) / 255, 1)))
  439. Blend_Apply(Blend_ColorDodge_Effect);
  440. doFullBlend = true;
  441. }
  442. else
  443. {
  444. #define Blend_ColorDodge_Layer(A,B) \
  445. std::min(255, ((((int) A) << 8 ) / std::max((((255 - B) * aBlendAlpha) + (255 * (255 - aBlendAlpha))) / 255, 1)))
  446. Blend_Apply(Blend_ColorDodge_Layer);
  447. doFullBlend = true;
  448. }
  449. }
  450. else if ((mixType == 'Ovrl') || (mixType == 'over')) // Overlay
  451. {
  452. #define ChannelBlend_Overlay(A,B) \
  453. (A < 128) ? \
  454. (2 * A * B / 255) : \
  455. (255 - (2 * (255 - A) * (255 - B) / 255))
  456. Blend_Apply(ChannelBlend_Overlay);
  457. }
  458. else if ((mixType == 'SftL') || (mixType == 'sLit')) // Soft Light
  459. {
  460. #define ChannelBlend_SoftLight(A,B) \
  461. (B < 128) ? (A - (255 - clamp(2 * B, 0, 255))*A*(255 - A)/255/255) : \
  462. (A < 64) ? A + ((2*B - 255) * ((((16*A - 12*255)*A/255 + 4*255) * A / 255) - A) / 255) : \
  463. A + ((2*B - 255) * (gSqrtTable[A] - A) / 255)
  464. Blend_Apply(ChannelBlend_SoftLight);
  465. }
  466. else if ((mixType == 'HrdL') || (mixType == 'hLit')) // Hard Light
  467. {
  468. #define Blend_HardLight(A,B) \
  469. (B < 128) ? \
  470. (2 * B * A / 255) : \
  471. (255 - (2 * (255 - B) * (255 - A) / 255))
  472. Blend_Apply(Blend_HardLight);
  473. }
  474. else if ((mixType == 'vivL') || (mixType == 'vLit')) // Vivid Light
  475. {
  476. if ((dest->mX + x == 149) && (dest->mY + y == 218))
  477. {
  478. /*aDestColor->a = 255;
  479. aDestColor->r = 0;
  480. aDestColor->g = 255;
  481. aDestColor->b = 0;*/
  482. }
  483. if (mixType == 'vivL') // Effect
  484. {
  485. int blendVal = (aBlendAlpha * aSrcColor->a / 255);
  486. #define Blend_VividLight_Effect(A,B) \
  487. (B < 128) ? \
  488. std::max(0, 255 - (((255 - (int) A) << 8 ) / \
  489. std::max((((2 * B * blendVal) + (255 * (255 - blendVal))) / 255), 1))) : \
  490. std::min(255, ((((int) A) << 8 ) / \
  491. std::max((((255 - B) * 2 * blendVal) + (255 * (255 - blendVal))) / 255, 1)))
  492. Blend_Apply(Blend_VividLight_Effect);
  493. doFullBlend = true;
  494. }
  495. else // Layer
  496. {
  497. #define Blend_VividLight_Layer(A,B) \
  498. (B < 128) ? \
  499. std::max(0, 255 - (((255 - (int) A) << 8 ) / \
  500. std::max(((2 * B * aBlendAlpha) + (255 * (255 - aBlendAlpha))) / 255, 1))) : \
  501. std::min(255, ((((int) A) << 8 ) / \
  502. std::max((((255 - B) * 2 * aBlendAlpha) + (255 * (255 - aBlendAlpha))) / 255, 1)))
  503. Blend_Apply(Blend_VividLight_Layer);
  504. //doAltBlend = (mixType == 'vivL');
  505. //doFullBlend = !doAltBlend;
  506. doFullBlend = true;
  507. }
  508. }
  509. else if (mixType == 'lLit') // Linear Light (Layer)
  510. {
  511. // Alternate blend mode
  512. /*#define Blend_LinearLight_Layer(A,B) \
  513. (B < 128) ? \
  514. (255 - std::min(255, (255 - A) + (255 - B*2))) : \
  515. std::min(255, A + (B - 128) * 2)
  516. Blend_Apply(Blend_LinearLight_Layer); */
  517. }
  518. else if (mixType == 'linL') // Linear Light (Effect)
  519. {
  520. int newDestAlpha = aDestColor->a + ((255 - aDestColor->a) * aBlendedColor.a) / 255;
  521. if (newDestAlpha > 0)
  522. {
  523. #define Blend_LinearLight(A,B) \
  524. (B < 128) ? \
  525. (255 - std::min(255, \
  526. (((255 - B*2) * aSrcAlpha) + ((255 - A) * aDestColor->a)) / newDestAlpha)) : \
  527. std::min(255, (((B - 128)*2 * aSrcAlpha) + (A * aDestColor->a)) / newDestAlpha)
  528. Blend_Apply(Blend_LinearLight);
  529. }
  530. doFullBlend = true;
  531. }
  532. else if ((mixType == 'pinL') || (mixType == 'pLit')) // Pin Light
  533. {
  534. #define ChannelBlend_PinLight(A,B) \
  535. (B < 128) ? \
  536. std::min((int) A, (int) B * 2) : \
  537. std::max((int) A, (int) (B - 128) * 2)
  538. aBlendedColor.r = ChannelBlend_PinLight((int) aDestColor->r, (int) aSrcColor->r);
  539. aBlendedColor.g = ChannelBlend_PinLight((int) aDestColor->g, (int) aSrcColor->g);
  540. aBlendedColor.b = ChannelBlend_PinLight((int) aDestColor->b, (int) aSrcColor->b);
  541. }
  542. else if ((mixType == 'hdMx') || (mixType == 'hMix')) // Hard Mix
  543. {
  544. if (mixType == 'hdMx') // Effect
  545. {
  546. int scale = 255 * 255 / std::max(255 - (aBlendAlpha * aSrcColor->a)/255, 1);
  547. #define Blend_Scale(A,S) \
  548. (((A) - 128)*S/255+128)
  549. #define Blend_HardMix(A,B) \
  550. clamp(Blend_Scale(A,scale) - Blend_Scale(255 - B,scale) + (255 - B), 0, 255)
  551. Blend_Apply(Blend_HardMix);
  552. doFullBlend = true;
  553. }
  554. else // Layer
  555. {
  556. int scale = 255 * 255 / std::max(255 - aBlendAlpha, 1);
  557. #define Blend_Scale(A,S) \
  558. (((A) - 128)*S/255+128)
  559. #define Blend_HardMix_Layer(A,B) \
  560. clamp(Blend_Scale(A,scale) - Blend_Scale(255 - B,scale) + (255 - B), 0, 255)
  561. Blend_Apply(Blend_HardMix_Layer);
  562. doFullBlend = true;
  563. }
  564. }
  565. else if ((mixType == 'Dfrn') || (mixType == 'diff')) // Difference
  566. {
  567. /*#define ChannelBlend_Difference(A,B) \
  568. abs(A - B*aBlendAlpha/255)
  569. Blend_Apply(ChannelBlend_Difference);
  570. doAltBlend = (mixType == 'Dfrn');
  571. doFullBlend = !doAltBlend;*/
  572. #define ChannelBlend_Difference(A,B) \
  573. abs(A - B*aSrcAlpha/255)
  574. Blend_Apply(ChannelBlend_Difference);
  575. //doAltBlend = (mixType == 'Dfrn');
  576. //doFullBlend = !doAltBlend;
  577. //doAltBlend = true;
  578. doFullBlend = true;
  579. }
  580. else if ((mixType == 'Xclu') || (mixType == 'smud')) // Exclusion
  581. {
  582. #define ChannelBlend_Exclusion(A,B) \
  583. (A + B*aBlendAlpha/255 - 2*A*B*aBlendAlpha/255/255)
  584. Blend_Apply(ChannelBlend_Exclusion);
  585. doAltBlend = (mixType == 'Xclu');
  586. doFullBlend = !doAltBlend;
  587. }
  588. else if ((mixType == 'subt') || (mixType == 'fsub')) // Subtract
  589. {
  590. if (mixType == 'fsub')
  591. {
  592. #define ChannelBlend_Subtract(A,B) \
  593. std::max(0, A - B)
  594. Blend_Apply(ChannelBlend_Subtract);
  595. }
  596. else //TODO: Double check the Effect version here...
  597. {
  598. #define ChannelBlend_Subtract_Effect(A,B) \
  599. std::max(0, A - B*aBlendAlpha/255)
  600. Blend_Apply(ChannelBlend_Subtract_Effect);
  601. doAltBlend = (mixType == 'subt');
  602. }
  603. }
  604. else if ((mixType == 'divi') || (mixType == 'fdiv')) // Divide
  605. {
  606. #define ChannelBlend_Divide(A,B) \
  607. std::min(255, A*255 / std::max(B, 1))
  608. Blend_Apply(ChannelBlend_Divide);
  609. }
  610. else if ((mixType == 'H ') || (mixType == 'hue ')) // Hue
  611. {
  612. aBlendedColor = SetLum(SetSat(*aSrcColor, Sat(*aDestColor)), Lum(*aDestColor));
  613. aBlendedColor.a = aSrcAlpha;
  614. }
  615. else if ((mixType == 'Strt') || (mixType == 'sat ')) // Saturation
  616. {
  617. aBlendedColor = SetLum(SetSat(*aDestColor, Sat(*aSrcColor)), Lum(*aDestColor));
  618. aBlendedColor.a = aSrcAlpha;
  619. }
  620. else if ((mixType == 'Clr ') || (mixType == 'colr')) // Color
  621. {
  622. aBlendedColor = SetLum(*aSrcColor, Lum(*aDestColor));
  623. aBlendedColor.a = aSrcAlpha;
  624. }
  625. else if ((mixType == 'Lmns') || (mixType == 'lum ')) // Luminosity
  626. {
  627. aBlendedColor = SetLum(*aDestColor, Lum(*aSrcColor));
  628. aBlendedColor.a = aSrcAlpha;
  629. }
  630. else
  631. {
  632. BF_FATAL("Unknown blend type");
  633. }
  634. //if (aDestColor->a != 0)
  635. {
  636. if ((mixType == 'lddg') || (mixType == 'lnDg')) // Linear Dodge
  637. {
  638. int newDestAlpha = 255;
  639. int a = aSrcAlpha;
  640. if (aDestColor->a != 255)
  641. newDestAlpha = aDestColor->a + ((255 - aDestColor->a) * aSrcAlpha) / 255;
  642. int blendThing = 255 - ((255 - aBlendAlpha) * aDestColor->a / 255);
  643. #define LinearDodge_Layer(A,B) \
  644. std::min(255, A + B * blendThing / 255) + ((255 - blendThing) * B) / 255
  645. WideColor blendWColor =
  646. {LinearDodge_Layer((int) aDestColor->r, (int) aSrcColor->r),
  647. LinearDodge_Layer((int) aDestColor->g, (int) aSrcColor->g),
  648. LinearDodge_Layer((int) aDestColor->b, (int) aSrcColor->b),
  649. aSrcAlpha};
  650. if (newDestAlpha != 0)
  651. {
  652. a = 255 * blendWColor.a / newDestAlpha;
  653. int ba = aDestColor->a;
  654. int boma = 255 - ba;
  655. blendWColor.r = ((blendWColor.r * ba) + (aSrcColor->r * boma)) / 255;
  656. blendWColor.g = ((blendWColor.g * ba) + (aSrcColor->g * boma)) / 255;
  657. blendWColor.b = ((blendWColor.b * ba) + (aSrcColor->b * boma)) / 255;
  658. }
  659. int oma = 255 - a;
  660. aDestColor->a = newDestAlpha;
  661. aDestColor->r = std::min(255, ((blendWColor.r * a) + (aDestColor->r * oma)) / 255);
  662. aDestColor->g = std::min(255, ((blendWColor.g * a) + (aDestColor->g * oma)) / 255);
  663. aDestColor->b = std::min(255, ((blendWColor.b * a) + (aDestColor->b * oma)) / 255);
  664. }
  665. else if ((mixType == 'lbrn') || (mixType == 'lnBn')) // Linear Burn
  666. {
  667. int blendThing = 255 - ((255 - aBlendAlpha) * aDestColor->a / 255);
  668. #define Blend_LinearDodge_Layer(A,B) \
  669. 255 - (std::min(255, ((255 - A) + (255 - B) * blendThing / 255)) + ((255 - blendThing) * (255 - B)) / 255)
  670. //255 - ((255 - A) + (255 - B))
  671. WideColor blendWColor =
  672. {Blend_LinearDodge_Layer((int) aDestColor->r, (int) aSrcColor->r),
  673. Blend_LinearDodge_Layer((int) aDestColor->g, (int) aSrcColor->g),
  674. Blend_LinearDodge_Layer((int) aDestColor->b, (int) aSrcColor->b),
  675. aSrcAlpha};
  676. int newDestAlpha = 255;
  677. int a = blendWColor.a;
  678. if (aDestColor->a != 255)
  679. newDestAlpha = aDestColor->a + ((255 - aDestColor->a) * blendWColor.a) / 255;
  680. if (newDestAlpha != 0)
  681. {
  682. a = 255 * blendWColor.a / newDestAlpha;
  683. int ba = aDestColor->a;
  684. int boma = 255 - aDestColor->a;
  685. blendWColor.r = ((blendWColor.r * ba) + (aSrcColor->r * boma)) / 255;
  686. blendWColor.g = ((blendWColor.g * ba) + (aSrcColor->g * boma)) / 255;
  687. blendWColor.b = ((blendWColor.b * ba) + (aSrcColor->b * boma)) / 255;
  688. }
  689. int oma = 255 - a;
  690. aDestColor->a = newDestAlpha;
  691. aDestColor->r = std::max(0, ((blendWColor.r * a) + (aDestColor->r * oma)) / 255);
  692. aDestColor->g = std::max(0, ((blendWColor.g * a) + (aDestColor->g * oma)) / 255);
  693. aDestColor->b = std::max(0, ((blendWColor.b * a) + (aDestColor->b * oma)) / 255);
  694. }
  695. else if ((mixType == 'lLit') || (mixType == 'linL')) // Linear Light
  696. {
  697. int blendThing = 255 - ((255 - aBlendAlpha) * aDestColor->a / 255);
  698. #define LinearLight_Contrib(A,B) \
  699. (B < 128) ? \
  700. (255 - (std::min(255, ((255 - A) + (255 - B*2) * blendThing / 255)) + ((255 - blendThing) * (255 - B*2)) / 255)) : \
  701. (std::min(255, A + (B - 128)*2 * blendThing / 255) + ((255 - blendThing) * (B - 128)*2) / 255)
  702. //((B - 128)*2 + A)
  703. WideColor blendWColor =
  704. {LinearLight_Contrib((int) aDestColor->r, (int) aSrcColor->r),
  705. LinearLight_Contrib((int) aDestColor->g, (int) aSrcColor->g),
  706. LinearLight_Contrib((int) aDestColor->b, (int) aSrcColor->b),
  707. aSrcAlpha};
  708. int newDestAlpha = 255;
  709. int a = blendWColor.a;
  710. if (aDestColor->a != 255)
  711. newDestAlpha = aDestColor->a + ((255 - aDestColor->a) * blendWColor.a) / 255;
  712. if (newDestAlpha != 0)
  713. {
  714. a = 255 * blendWColor.a / newDestAlpha;
  715. int ba = aDestColor->a;
  716. int boma = 255 - aDestColor->a;
  717. blendWColor.r = ((blendWColor.r * ba) + (aSrcColor->r * boma)) / 255;
  718. blendWColor.g = ((blendWColor.g * ba) + (aSrcColor->g * boma)) / 255;
  719. blendWColor.b = ((blendWColor.b * ba) + (aSrcColor->b * boma)) / 255;
  720. }
  721. int oma = 255 - a;
  722. aDestColor->a = newDestAlpha;
  723. aDestColor->r = clamp((((blendWColor.r * a) + (aDestColor->r * oma)) / 255), 0, 255);
  724. aDestColor->g = clamp((((blendWColor.g * a) + (aDestColor->g * oma)) / 255), 0, 255);
  725. aDestColor->b = clamp((((blendWColor.b * a) + (aDestColor->b * oma)) / 255), 0, 255);
  726. }
  727. else if (doReverseBlend)
  728. {
  729. int newDestAlpha = 255;
  730. int a = aDestColor->a;
  731. if (aDestColor->a != 255)
  732. newDestAlpha = aBlendedColor.a + ((255 - aBlendedColor.a) * aDestColor->a) / 255;
  733. if (newDestAlpha != 0)
  734. a = 255 * aDestColor->a / newDestAlpha;
  735. int oma = 255 - a;
  736. aDestColor->a = newDestAlpha;
  737. aDestColor->r = ((aDestColor->r * a) + (aBlendedColor.r * oma)) / 255;
  738. aDestColor->g = ((aDestColor->g * a) + (aBlendedColor.g * oma)) / 255;
  739. aDestColor->b = ((aDestColor->b * a) + (aBlendedColor.b * oma)) / 255;
  740. }
  741. else if (doFullBlend)
  742. {
  743. if ((dest->mX + x == 231) && (dest->mY + y == 183))
  744. {
  745. /*aBlendedColor.a = 255;
  746. aBlendedColor.r = 0;
  747. aBlendedColor.g = 255;
  748. aBlendedColor.b = 0;*/
  749. }
  750. int newDestAlpha = 255;
  751. int a = aBlendedColor.a;
  752. if (aDestColor->a != 255)
  753. newDestAlpha = aDestColor->a + ((255 - aDestColor->a) * aBlendedColor.a) / 255;
  754. /*if (newDestAlpha != 0)
  755. {
  756. //a = 255 * aSrcColor->a / newDestAlpha;
  757. int ba = aDestColor->a;
  758. int boma = 255 - ba;
  759. aBlendedColor.r = ((aBlendedColor.r * ba) + (aSrcColor->r * boma)) / 255;
  760. aBlendedColor.g = ((aBlendedColor.g * ba) + (aSrcColor->g * boma)) / 255;
  761. aBlendedColor.b = ((aBlendedColor.b * ba) + (aSrcColor->b * boma)) / 255;
  762. }*/
  763. if (newDestAlpha != 0)
  764. {
  765. //a = 255 * aSrcColor->a / newDestAlpha;
  766. int ba = 255 * aDestColor->a / newDestAlpha;
  767. int boma = 255 - ba;
  768. aBlendedColor.r = ((aBlendedColor.r * ba) + (aSrcColor->r * boma)) / 255;
  769. aBlendedColor.g = ((aBlendedColor.g * ba) + (aSrcColor->g * boma)) / 255;
  770. aBlendedColor.b = ((aBlendedColor.b * ba) + (aSrcColor->b * boma)) / 255;
  771. //}
  772. //if (aBlendedColor.a
  773. /*int coma = (255 * 255 * a) / (255 * a + aDestColor->a * (255 - a));
  774. //int ca = 255 - aBlendedColor.a;
  775. //coma = gSqrtTable[coma];
  776. //coma = std::min(255, coma * 255);
  777. if (coma != 255)
  778. {
  779. }
  780. coma = 255;
  781. int ca = 255 - coma;
  782. aDestColor->a = newDestAlpha;
  783. aDestColor->r = ((aDestColor->r * ca) + (aBlendedColor.r * coma)) / 255;
  784. aDestColor->g = ((aDestColor->g * ca) + (aBlendedColor.g * coma)) / 255;
  785. aDestColor->b = ((aDestColor->b * ca) + (aBlendedColor.b * coma)) / 255;*/
  786. aDestColor->a = newDestAlpha;
  787. aDestColor->r = aBlendedColor.r;
  788. aDestColor->g = aBlendedColor.g;
  789. aDestColor->b = aBlendedColor.b;
  790. }
  791. else
  792. {
  793. aDestColor->a = 0;
  794. }
  795. /*int oma = 255 - a;
  796. aDestColor->a = newDestAlpha;
  797. aDestColor->r = aBlendedColor.r;
  798. aDestColor->g = aBlendedColor.g;
  799. aDestColor->b = aBlendedColor.b;*/
  800. /*int newDestAlpha = 255;
  801. int a = aBlendedColor.a;
  802. if (aDestColor->a != 255)
  803. newDestAlpha = aDestColor->a + ((255 - aDestColor->a) * aBlendedColor.a) / 255;
  804. int oma = 255 - a;
  805. aDestColor->a = newDestAlpha;
  806. aDestColor->r = aBlendedColor.r;
  807. aDestColor->g = aBlendedColor.g;
  808. aDestColor->b = aBlendedColor.b;
  809. if (newDestAlpha != 0)
  810. {
  811. a = 255 * aBlendedColor.a / newDestAlpha;
  812. int ba = aDestColor->a;
  813. int boma = 255 - ba;
  814. aBlendedColor.r = ((aDestColor->r * ba) + (aSrcColor->r * boma)) / 255;
  815. aBlendedColor.g = ((aDestColor->g * ba) + (aSrcColor->g * boma)) / 255;
  816. aBlendedColor.b = ((aDestColor->b * ba) + (aSrcColor->b * boma)) / 255;
  817. }*/
  818. }
  819. else if (doAltBlend)
  820. {
  821. if ((dest->mX + x == 134) && (dest->mY + y == 153))
  822. {
  823. /*aDestColor->a = 255;
  824. aDestColor->r = 0;
  825. aDestColor->g = 255;
  826. aDestColor->b = 0;*/
  827. }
  828. int newDestAlpha = 255;
  829. if (aDestColor->a != 255)
  830. newDestAlpha = aDestColor->a + ((255 - aDestColor->a) * aSrcAlpha) / 255;
  831. int destContrib = (255 - aSrcColor->a)*aDestColor->a;
  832. int srcContrib = (255 - aDestColor->a)*aSrcColor->a;
  833. int blendContrib = aSrcColor->a * aDestColor->a;
  834. int divTot = destContrib + srcContrib + blendContrib;
  835. if (divTot > 0)
  836. {
  837. aDestColor->r = ((destContrib * aDestColor->r) + (srcContrib * aSrcColor->r) + (blendContrib * aBlendedColor.r)) / divTot;
  838. aDestColor->g = ((destContrib * aDestColor->g) + (srcContrib * aSrcColor->g) + (blendContrib * aBlendedColor.g)) / divTot;
  839. aDestColor->b = ((destContrib * aDestColor->b) + (srcContrib * aSrcColor->b) + (blendContrib * aBlendedColor.b)) / divTot;
  840. aDestColor->a = newDestAlpha;
  841. }
  842. }
  843. else
  844. {
  845. if ((x == 140) && (y == 83))
  846. {
  847. }
  848. int newDestAlpha = 255;
  849. int a = aBlendedColor.a;
  850. if (aDestColor->a != 255)
  851. newDestAlpha = aDestColor->a + ((255 - aDestColor->a) * aBlendedColor.a) / 255;
  852. if (newDestAlpha != 0)
  853. {
  854. a = 255 * aBlendedColor.a / newDestAlpha;
  855. int ba = aDestColor->a;
  856. int boma = 255 - aDestColor->a;
  857. aBlendedColor.r = ((aBlendedColor.r * ba) + (aSrcColor->r * boma)) / 255;
  858. aBlendedColor.g = ((aBlendedColor.g * ba) + (aSrcColor->g * boma)) / 255;
  859. aBlendedColor.b = ((aBlendedColor.b * ba) + (aSrcColor->b * boma)) / 255;
  860. }
  861. int oma = 255 - a;
  862. aDestColor->a = newDestAlpha;
  863. aDestColor->r = ((aBlendedColor.r * a) + (aDestColor->r * oma)) / 255;
  864. aDestColor->g = ((aBlendedColor.g * a) + (aDestColor->g * oma)) / 255;
  865. aDestColor->b = ((aBlendedColor.b * a) + (aDestColor->b * oma)) / 255;
  866. }
  867. }
  868. aDestColor++;
  869. aSrcColor++;
  870. }
  871. }
  872. }
  873. void Beefy::BlendImagesTogether(ImageData* bottomImage, ImageData* topImage, ImageData* alphaImage)
  874. {
  875. for (int y = alphaImage->mY; y < alphaImage->mY + alphaImage->mHeight; y++)
  876. {
  877. PackedColor* topColor = (PackedColor*) (topImage->mBits + (alphaImage->mX - topImage->mX) + ((y - topImage->mY) * topImage->mWidth));
  878. PackedColor* botColor = (PackedColor*) (bottomImage->mBits + (alphaImage->mX - bottomImage->mX) + ((y - bottomImage->mY) * bottomImage->mWidth));
  879. PackedColor* alphaColor = (PackedColor*) (alphaImage->mBits + (alphaImage->mX - alphaImage->mX) + ((y - alphaImage->mY) * alphaImage->mWidth));
  880. for (int x = 0; x < alphaImage->mWidth; x++)
  881. {
  882. int a = alphaColor->a;
  883. int oma = 255 - a;
  884. int newDestAlpha = ((topColor->a * a) + (botColor->a * oma)) / 255;
  885. if (newDestAlpha != 0)
  886. {
  887. int ca = (255 * topColor->a * a) / ((topColor->a * a) + (botColor->a * oma));
  888. int coma = 255 - ca;
  889. botColor->a = newDestAlpha;
  890. botColor->r = ((topColor->r * ca) + (botColor->r * coma)) / 255;
  891. botColor->g = ((topColor->g * ca) + (botColor->g * coma)) / 255;
  892. botColor->b = ((topColor->b * ca) + (botColor->b * coma)) / 255;
  893. }
  894. topColor++;
  895. botColor++;
  896. alphaColor++;
  897. }
  898. }
  899. }
  900. void Beefy::SetImageAlpha(ImageData* image, ImageData* alphaImage)
  901. {
  902. for (int i = 0; i < image->mWidth * image->mHeight; i++)
  903. image->mBits[i] = image->mBits[i] & 0x00FFFFFF;
  904. for (int y = alphaImage->mY; y < alphaImage->mY + alphaImage->mHeight; y++)
  905. {
  906. PackedColor* aColor = (PackedColor*) (image->mBits + (alphaImage->mX - image->mX) + ((y - image->mY) * image->mWidth));
  907. PackedColor* alphaColor = (PackedColor*) (alphaImage->mBits + (alphaImage->mX - alphaImage->mX) + ((y - alphaImage->mY) * alphaImage->mWidth));
  908. for (int x = 0; x < alphaImage->mWidth; x++)
  909. {
  910. aColor->a = alphaColor->a;
  911. aColor++;
  912. alphaColor++;
  913. }
  914. }
  915. }
  916. void Beefy::MultiplyImageAlpha(ImageData* image, ImageData* alphaImage)
  917. {
  918. for (int y = alphaImage->mY; y < alphaImage->mY + alphaImage->mHeight; y++)
  919. {
  920. PackedColor* aColor = (PackedColor*) (image->mBits + (alphaImage->mX - image->mX) + ((y - image->mY) * image->mWidth));
  921. PackedColor* alphaColor = (PackedColor*) (alphaImage->mBits + (alphaImage->mX - alphaImage->mX) + ((y - alphaImage->mY) * alphaImage->mWidth));
  922. for (int x = 0; x < alphaImage->mWidth; x++)
  923. {
  924. aColor->a = aColor->a * alphaColor->a / 255;
  925. aColor++;
  926. alphaColor++;
  927. }
  928. }
  929. }
  930. void Beefy::SetImageAlpha(ImageData* image, int alpha)
  931. {
  932. int size = image->mWidth * image->mHeight;
  933. for (int i = 0; i < size; i++)
  934. image->mBits[i] |= 0xFF000000;
  935. }
  936. void Beefy::CopyImageBits(ImageData* dest, ImageData* src)
  937. {
  938. for (int y = src->mY; y < src->mY + src->mHeight; y++)
  939. {
  940. PackedColor* aDestColor = (PackedColor*) (dest->mBits + (src->mX - dest->mX) + ((y - dest->mY) * dest->mWidth));
  941. PackedColor* aSrcColor = (PackedColor*) (src->mBits + (src->mX - src->mX) + ((y - src->mY) * src->mWidth));
  942. for (int x = 0; x < src->mWidth; x++)
  943. {
  944. *aDestColor = *aSrcColor;
  945. aDestColor++;
  946. aSrcColor++;
  947. }
  948. }
  949. }