Normalize.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Processing/ImageObjectImpl.h>
  9. #include <Processing/ImageFlags.h>
  10. namespace ImageProcessingAtom
  11. {
  12. template<const int qBits>
  13. static void AdjustScaleForQuantization(float fBaseValue, float fBaseLine, float& cScale, float& cMinColor, float& cMaxColor)
  14. {
  15. const int qOne = (1 << qBits) - 1;
  16. const int qUpperBits = (8 - qBits);
  17. const int qLowerBits = qBits - qUpperBits;
  18. const int v = int(floor(fBaseValue * qOne));
  19. int v0 = v - (v != 0);
  20. int v1 = v + 0;
  21. int v2 = v + (v != qOne);
  22. v0 = (v0 << qUpperBits) | (v0 >> qLowerBits);
  23. v1 = (v1 << qUpperBits) | (v1 >> qLowerBits);
  24. v2 = (v2 << qUpperBits) | (v2 >> qLowerBits);
  25. const float f0 = v0 / 255.0f;
  26. const float f1 = v1 / 255.0f;
  27. const float f2 = v2 / 255.0f;
  28. float fBaseLock = -1;
  29. if (fabsf(f0 - fBaseValue) < fabsf(fBaseLock - fBaseValue))
  30. {
  31. fBaseLock = f0;
  32. }
  33. if (fabsf(f1 - fBaseValue) < fabsf(fBaseLock - fBaseValue))
  34. {
  35. fBaseLock = f1;
  36. }
  37. if (fabsf(f2 - fBaseValue) < fabsf(fBaseLock - fBaseValue))
  38. {
  39. fBaseLock = f2;
  40. }
  41. float lScale = (1.0f - fBaseLock) / (1.0f - fBaseLine);
  42. float vScale = (1.0f - fBaseValue) / (1.0f - fBaseLine);
  43. float sScale = lScale / vScale;
  44. float csScale = (cScale / sScale);
  45. float csBias = cMinColor - (1.0f - sScale) * (cScale / sScale);
  46. if ((csBias > 0.0f) && ((csScale + csBias) < 1.0f))
  47. {
  48. cMinColor = csBias;
  49. cScale = csScale;
  50. cMaxColor = csScale + csBias;
  51. }
  52. }
  53. ///////////////////////////////////////////////////////////////////////////////////
  54. void CImageObject::NormalizeImageRange(EColorNormalization eColorNorm, EAlphaNormalization eAlphaNorm, bool bMaintainBlack, int nExponentBits)
  55. {
  56. if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
  57. {
  58. AZ_Assert(false, "%s: unsupported source format", __FUNCTION__);
  59. return;
  60. }
  61. uint32 dwWidth, dwHeight, dwMips;
  62. GetExtent(dwWidth, dwHeight, dwMips);
  63. // find image's range, can be negative
  64. float cMinColor[4] = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
  65. float cMaxColor[4] = { -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX };
  66. for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip)
  67. {
  68. uint8* pSrcMem;
  69. uint32 dwSrcPitch;
  70. GetImagePointer(dwMip, pSrcMem, dwSrcPitch);
  71. dwHeight = GetHeight(dwMip);
  72. dwWidth = GetWidth(dwMip);
  73. for (uint32 dwY = 0; dwY < dwHeight; ++dwY)
  74. {
  75. const float* pSrcPix = (float*)&pSrcMem[dwY * dwSrcPitch];
  76. for (uint32 dwX = 0; dwX < dwWidth; ++dwX)
  77. {
  78. cMinColor[0] = AZ::GetMin(cMinColor[0], pSrcPix[0]);
  79. cMinColor[1] = AZ::GetMin(cMinColor[1], pSrcPix[1]);
  80. cMinColor[2] = AZ::GetMin(cMinColor[2], pSrcPix[2]);
  81. cMinColor[3] = AZ::GetMin(cMinColor[3], pSrcPix[3]);
  82. cMaxColor[0] = AZ::GetMax(cMaxColor[0], pSrcPix[0]);
  83. cMaxColor[1] = AZ::GetMax(cMaxColor[1], pSrcPix[1]);
  84. cMaxColor[2] = AZ::GetMax(cMaxColor[2], pSrcPix[2]);
  85. cMaxColor[3] = AZ::GetMax(cMaxColor[3], pSrcPix[3]);
  86. pSrcPix += 4;
  87. }
  88. }
  89. }
  90. if (bMaintainBlack)
  91. {
  92. cMinColor[0] = AZ::GetMin(0.f, cMinColor[0]);
  93. cMinColor[1] = AZ::GetMin(0.f, cMinColor[1]);
  94. cMinColor[2] = AZ::GetMin(0.f, cMinColor[2]);
  95. cMinColor[3] = AZ::GetMin(0.f, cMinColor[3]);
  96. }
  97. AZ_Assert(cMaxColor[0] >= cMinColor[0] && cMaxColor[1] >= cMinColor[1] &&
  98. cMaxColor[2] >= cMinColor[2] && cMaxColor[3] >= cMinColor[3], "bad color range");
  99. // some graceful threshold to avoid extreme cases
  100. if (cMaxColor[0] - cMinColor[0] < (3.f / 255))
  101. {
  102. cMinColor[0] = AZ::GetMax(0.f, cMinColor[0] - (2.f / 255));
  103. cMaxColor[0] = AZ::GetMin(1.f, cMaxColor[0] + (2.f / 255));
  104. }
  105. if (cMaxColor[1] - cMinColor[1] < (3.f / 255))
  106. {
  107. cMinColor[1] = AZ::GetMax(0.f, cMinColor[1] - (2.f / 255));
  108. cMaxColor[1] = AZ::GetMin(1.f, cMaxColor[1] + (2.f / 255));
  109. }
  110. if (cMaxColor[2] - cMinColor[2] < (3.f / 255))
  111. {
  112. cMinColor[2] = AZ::GetMax(0.f, cMinColor[2] - (2.f / 255));
  113. cMaxColor[2] = AZ::GetMin(1.f, cMaxColor[2] + (2.f / 255));
  114. }
  115. if (cMaxColor[3] - cMinColor[3] < (3.f / 255))
  116. {
  117. cMinColor[3] = AZ::GetMax(0.f, cMinColor[3] - (2.f / 255));
  118. cMaxColor[3] = AZ::GetMin(1.f, cMaxColor[3] + (2.f / 255));
  119. }
  120. // calculate range to normalize to
  121. const float fMaxExponent = powf(2.0f, (float)nExponentBits) - 1.0f;
  122. const float cUprValue = powf(2.0f, fMaxExponent);
  123. if (eColorNorm == eColorNormalization_PassThrough)
  124. {
  125. cMinColor[0] = cMinColor[1] = cMinColor[2] = 0.f;
  126. cMaxColor[0] = cMaxColor[1] = cMaxColor[2] = 1.f;
  127. }
  128. // don't touch alpha channel if not used
  129. if (eAlphaNorm == eAlphaNormalization_SetToZero)
  130. {
  131. // Store the range explicitly into the structure for read-back.
  132. // The formats which request range expansion don't support alpha.
  133. cMinColor[3] = 0.f;
  134. cMaxColor[3] = cUprValue;
  135. }
  136. else if (eAlphaNorm == eAlphaNormalization_PassThrough)
  137. {
  138. cMinColor[3] = 0.f;
  139. cMaxColor[3] = 1.f;
  140. }
  141. // get the origins of the color model's lattice for the range of values
  142. // these values need to be encoded as precise as possible under quantization
  143. AZ::Vector4 cScale = AZ::Vector4(cMaxColor[0] - cMinColor[0], cMaxColor[1] - cMinColor[1],
  144. cMaxColor[2] - cMinColor[2], cMaxColor[3] - cMinColor[3]);
  145. #if 0
  146. // NOTE: disabled for now, in the future we can turn this on to force availability
  147. // of value to guarantee for example perfect grey-scales (using YFF)
  148. AZ::Vector4 cBaseLines = AZ::Vector4(0.0f, 0.0f, 0.0f, 0.0f);
  149. switch (GetImageFlags() & EIF_Colormodel)
  150. {
  151. case EIF_Colormodel_RGB:
  152. cBaseLines = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
  153. break;
  154. case EIF_Colormodel_CIE:
  155. cBaseLines = Vec4(0.0f, 1.f / 3, 1.f / 3, 0.0f);
  156. break;
  157. case EIF_Colormodel_IRB:
  158. cBaseLines = Vec4(0.0f, 1.f / 2, 1.f / 2, 0.0f);
  159. break;
  160. case EIF_Colormodel_YCC:
  161. case EIF_Colormodel_YFF:
  162. cBaseLines = Vec4(1.f / 2, 0.0f, 1.f / 2, 0.0f);
  163. break;
  164. }
  165. Vec4 cBaseScale = cBaseLines;
  166. cBaseLines = cBaseLines - cMinColor;
  167. cBaseLines = cBaseLines / cScale;
  168. if ((cBaseLines.x > 0.0f) && (cBaseLines.x < 1.0f))
  169. {
  170. AdjustScaleForQuantization<5>(cBaseLines.x, cBaseScale.x, cScale.x, cMinColor.x, cMaxColor.x);
  171. }
  172. if ((cBaseLines.y > 0.0f) && (cBaseLines.y < 1.0f))
  173. {
  174. AdjustScaleForQuantization<6>(cBaseLines.y, cBaseScale.y, cScale.y, cMinColor.y, cMaxColor.y);
  175. }
  176. if ((cBaseLines.z > 0.0f) && (cBaseLines.z < 1.0f))
  177. {
  178. AdjustScaleForQuantization<5>(cBaseLines.z, cBaseScale.z, cScale.z, cMinColor.z, cMaxColor.z);
  179. }
  180. #endif
  181. // normalize the image
  182. AZ::Vector4 vMin = AZ::Vector4(cMinColor[0], cMinColor[1], cMinColor[2], cMinColor[3]);
  183. for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip)
  184. {
  185. uint8* pSrcMem;
  186. uint32 dwSrcPitch;
  187. GetImagePointer(dwMip, pSrcMem, dwSrcPitch);
  188. dwHeight = GetHeight(dwMip);
  189. dwWidth = GetWidth(dwMip);
  190. for (uint32 dwY = 0; dwY < dwHeight; ++dwY)
  191. {
  192. AZ::Vector4* pSrcPix = (AZ::Vector4*)&pSrcMem[dwY * dwSrcPitch];
  193. for (uint32 dwX = 0; dwX < dwWidth; ++dwX)
  194. {
  195. *pSrcPix = *pSrcPix - vMin;
  196. *pSrcPix = *pSrcPix / cScale;
  197. *pSrcPix = *pSrcPix * cUprValue;
  198. pSrcPix++;
  199. }
  200. }
  201. }
  202. // set up a range
  203. SetColorRange(AZ::Color(cMinColor[0], cMinColor[1], cMinColor[2], cMinColor[3]),
  204. AZ::Color(cMaxColor[0], cMaxColor[1], cMaxColor[2], cMaxColor[3]));
  205. // set up a flag
  206. AddImageFlags(EIF_RenormalizedTexture);
  207. }
  208. void CImageObject::ExpandImageRange([[maybe_unused]] EColorNormalization eColorMode, EAlphaNormalization eAlphaMode, int nExponentBits)
  209. {
  210. AZ_Assert(!((eAlphaMode != eAlphaNormalization_SetToZero) && (nExponentBits != 0)), "%s: Unexpected alpha mode", __FUNCTION__);
  211. if (!HasImageFlags(EIF_RenormalizedTexture))
  212. {
  213. return;
  214. }
  215. if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
  216. {
  217. AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__);
  218. return;
  219. }
  220. uint32 dwWidth, dwHeight, dwMips;
  221. GetExtent(dwWidth, dwHeight, dwMips);
  222. // calculate range to normalize to
  223. const float fMaxExponent = powf(2.0f, (float)nExponentBits) - 1.0f;
  224. float cUprValue = powf(2.0f, fMaxExponent);
  225. // find image's range, can be negative
  226. AZ::Color cMinColor = AZ::Color(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);
  227. AZ::Color cMaxColor = AZ::Color(-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX);
  228. GetColorRange(cMinColor, cMaxColor);
  229. // don't touch alpha channel if not used
  230. if (eAlphaMode == eAlphaNormalization_SetToZero)
  231. {
  232. // Overwrite the range explicitly into the structure.
  233. // The formats which request range expansion don't support alpha.
  234. cUprValue = cMaxColor.GetA();
  235. cMinColor.SetA(1.f);
  236. cMaxColor.SetA(1.f);
  237. }
  238. // expand the image
  239. const AZ::Vector4 cScale = cMaxColor.GetAsVector4() - cMinColor.GetAsVector4();
  240. for (uint32 dwMip = 0; dwMip < dwMips; ++dwMip)
  241. {
  242. uint8* pSrcMem;
  243. uint32 dwSrcPitch;
  244. GetImagePointer(dwMip, pSrcMem, dwSrcPitch);
  245. dwHeight = GetHeight(dwMip);
  246. dwWidth = GetWidth(dwMip);
  247. for (uint32 dwY = 0; dwY < dwHeight; ++dwY)
  248. {
  249. AZ::Vector4* pSrcPix = (AZ::Vector4*)&pSrcMem[dwY * dwSrcPitch];
  250. for (uint32 dwX = 0; dwX < dwWidth; ++dwX)
  251. {
  252. *pSrcPix = *pSrcPix / cUprValue;
  253. *pSrcPix = *pSrcPix * cScale;
  254. *pSrcPix = *pSrcPix + cMinColor.GetAsVector4();
  255. pSrcPix++;
  256. }
  257. }
  258. }
  259. // set up a range
  260. SetColorRange(AZ::Color(0.0f, 0.0f, 0.0f, 0.0f), AZ::Color(1.0f, 1.0f, 1.0f, 1.0f));
  261. // set up a flag
  262. RemoveImageFlags(EIF_RenormalizedTexture);
  263. }
  264. ///////////////////////////////////////////////////////////////////////////////////
  265. void CImageObject::NormalizeVectors(AZ::u32 firstMip, AZ::u32 maxMipCount)
  266. {
  267. if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
  268. {
  269. AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__);
  270. return;
  271. }
  272. uint32 lastMip = AZ::GetMin(firstMip + maxMipCount, GetMipCount());
  273. for (uint32 mip = firstMip; mip < lastMip; ++mip)
  274. {
  275. const uint32 pixelCount = GetPixelCount(mip);
  276. uint8* imageMem;
  277. uint32 pitch;
  278. GetImagePointer(mip, imageMem, pitch);
  279. float* pPixels = (float*)imageMem;
  280. for (uint32 i = 0; i < pixelCount; ++i, pPixels += 4)
  281. {
  282. AZ::Vector3 vNormal = AZ::Vector3(pPixels[0] * 2.0f - 1.0f, pPixels[1] * 2.0f - 1.0f, pPixels[2] * 2.0f - 1.0f);
  283. // TODO: every opposing vector addition produces the zero-vector for
  284. // normals on the entire sphere, in that case the forward vector [0,0,1]
  285. // isn't necessarily right and we should look at the adjacent normals
  286. // for a direction
  287. vNormal.NormalizeSafe();
  288. pPixels[0] = vNormal.GetX() * 0.5f + 0.5f;
  289. pPixels[1] = vNormal.GetY() * 0.5f + 0.5f;
  290. pPixels[2] = vNormal.GetZ() * 0.5f + 0.5f;
  291. }
  292. }
  293. }
  294. ///////////////////////////////////////////////////////////////////////////////////
  295. void CImageObject::ScaleAndBiasChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& scale, const AZ::Vector4& bias)
  296. {
  297. if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
  298. {
  299. AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__);
  300. return;
  301. }
  302. const uint32 lastMip = AZ::GetMin(firstMip + maxMipCount, GetMipCount());
  303. for (uint32 mip = firstMip; mip < lastMip; ++mip)
  304. {
  305. const uint32 pixelCount = GetPixelCount(mip);
  306. uint8* imageMem;
  307. uint32 pitch;
  308. GetImagePointer(mip, imageMem, pitch);
  309. float* pPixels = (float*)imageMem;
  310. for (uint32 i = 0; i < pixelCount; ++i, pPixels += 4)
  311. {
  312. pPixels[0] = pPixels[0] * scale.GetX() + bias.GetX();
  313. pPixels[1] = pPixels[1] * scale.GetY() + bias.GetY();
  314. pPixels[2] = pPixels[2] * scale.GetZ() + bias.GetZ();
  315. pPixels[3] = pPixels[3] * scale.GetW() + bias.GetW();
  316. }
  317. }
  318. }
  319. ///////////////////////////////////////////////////////////////////////////////////
  320. void CImageObject::ClampChannels(AZ::u32 firstMip, AZ::u32 maxMipCount, const AZ::Vector4& min, const AZ::Vector4& max)
  321. {
  322. if (GetPixelFormat() != ePixelFormat_R32G32B32A32F)
  323. {
  324. AZ_Assert(false, "%s: only supports source format A32B32G32R32F", __FUNCTION__);
  325. return;
  326. }
  327. const uint32 lastMip = AZ::GetMin(firstMip + maxMipCount, GetMipCount());
  328. for (uint32 mip = firstMip; mip < lastMip; ++mip)
  329. {
  330. const uint32 pixelCount = GetPixelCount(mip);
  331. uint8* imageMem;
  332. uint32 pitch;
  333. GetImagePointer(mip, imageMem, pitch);
  334. float* pPixels = (float*)imageMem;
  335. for (uint32 i = 0; i < pixelCount; ++i, pPixels += 4)
  336. {
  337. pPixels[0] = AZ::GetClamp(pPixels[0], float(min.GetX()), float(max.GetX()));
  338. pPixels[1] = AZ::GetClamp(pPixels[1], float(min.GetY()), float(max.GetY()));
  339. pPixels[2] = AZ::GetClamp(pPixels[2], float(min.GetZ()), float(max.GetZ()));
  340. pPixels[3] = AZ::GetClamp(pPixels[3], float(min.GetW()), float(max.GetW()));
  341. }
  342. }
  343. }
  344. } //namespace ImageProcessingAtom