ColorSpace.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../../idlib/precompiled.h"
  22. /*
  23. ================================================================================================
  24. Contains the ColorSpace conversion implementation.
  25. ================================================================================================
  26. */
  27. #include "ColorSpace.h"
  28. /*
  29. ================================================================================================
  30. To *Color-Convert RGB and YCoCg* ColorSpaces, use the following conversions:
  31. Y = [ 1/4 1/2 1/4] [R]
  32. Co = [ 1/2 0 -1/2] [G] + 128
  33. CG = [-1/4 1/2 -1/4] [B] + 128
  34. R = [ 1 1 -1] [Y]
  35. G = [ 1 0 1] [Co - 128]
  36. B = [ 1 -1 -1] [Cg - 128]
  37. ================================================================================================
  38. */
  39. #define RGB_TO_YCOCG_Y( r, g, b ) ( ( ( r + (g<<1) + b ) + 2 ) >> 2 )
  40. #define RGB_TO_YCOCG_CO( r, g, b ) ( ( ( (r<<1) - (b<<1) ) + 2 ) >> 2 )
  41. #define RGB_TO_YCOCG_CG( r, g, b ) ( ( ( - r + (g<<1) - b ) + 2 ) >> 2 )
  42. #define COCG_TO_R( co, cg ) ( co - cg )
  43. #define COCG_TO_G( co, cg ) ( cg )
  44. #define COCG_TO_B( co, cg ) ( - co - cg )
  45. /*
  46. ========================
  47. idColorSpace::ConvertRGBToYCoCg
  48. ========================
  49. */
  50. void idColorSpace::ConvertRGBToYCoCg( byte *dst, const byte *src, int width, int height ) {
  51. for ( int i = 0; i < width * height; i++ ) {
  52. int r = src[i*4+0];
  53. int g = src[i*4+1];
  54. int b = src[i*4+2];
  55. int a = src[i*4+3];
  56. dst[i*4+0] = CLAMP_BYTE( RGB_TO_YCOCG_Y( r, g, b ) );
  57. dst[i*4+1] = CLAMP_BYTE( RGB_TO_YCOCG_CO( r, g, b ) + 128 );
  58. dst[i*4+2] = CLAMP_BYTE( RGB_TO_YCOCG_CG( r, g, b ) + 128 );
  59. dst[i*4+3] = a;
  60. }
  61. }
  62. /*
  63. ========================
  64. idColorSpace::ConvertYCoCgToRGB
  65. ========================
  66. */
  67. void idColorSpace::ConvertYCoCgToRGB( byte *dst, const byte *src, int width, int height ) {
  68. for ( int i = 0; i < width * height; i++ ) {
  69. int y = src[i*4+0];
  70. int co = src[i*4+1] - 128;
  71. int cg = src[i*4+2] - 128;
  72. int a = src[i*4+3];
  73. dst[i*4+0] = CLAMP_BYTE( y + COCG_TO_R( co, cg ) );
  74. dst[i*4+1] = CLAMP_BYTE( y + COCG_TO_G( co, cg ) );
  75. dst[i*4+2] = CLAMP_BYTE( y + COCG_TO_B( co, cg ) );
  76. dst[i*4+3] = a;
  77. }
  78. }
  79. /*
  80. ========================
  81. idColorSpace::ConvertRGBToCoCg_Y
  82. ========================
  83. */
  84. void idColorSpace::ConvertRGBToCoCg_Y( byte *dst, const byte *src, int width, int height ) {
  85. for ( int i = 0; i < width * height; i++ ) {
  86. int r = src[i*4+0];
  87. int g = src[i*4+1];
  88. int b = src[i*4+2];
  89. //int a = src[i*4+3];
  90. dst[i*4+0] = CLAMP_BYTE( RGB_TO_YCOCG_CO( r, g, b ) + 128 );
  91. dst[i*4+1] = CLAMP_BYTE( RGB_TO_YCOCG_CG( r, g, b ) + 128 );
  92. dst[i*4+2] = 0;
  93. dst[i*4+3] = CLAMP_BYTE( RGB_TO_YCOCG_Y( r, g, b ) );
  94. }
  95. }
  96. /*
  97. ========================
  98. idColorSpace::ConvertCoCg_YToRGB
  99. ========================
  100. */
  101. void idColorSpace::ConvertCoCg_YToRGB( byte *dst, const byte *src, int width, int height ) {
  102. for ( int i = 0; i < width * height; i++ ) {
  103. int co = src[i*4+0] - 128;
  104. int cg = src[i*4+1] - 128;
  105. int a = src[i*4+2];
  106. int y = src[i*4+3];
  107. dst[i*4+0] = CLAMP_BYTE( y + COCG_TO_R( co, cg ) );
  108. dst[i*4+1] = CLAMP_BYTE( y + COCG_TO_G( co, cg ) );
  109. dst[i*4+2] = CLAMP_BYTE( y + COCG_TO_B( co, cg ) );
  110. dst[i*4+3] = a;
  111. }
  112. }
  113. /*
  114. ========================
  115. idColorSpace::ConvertCoCgSYToRGB
  116. A scale factor is encoded in the Z value to give better compression of
  117. the color channels.
  118. ========================
  119. */
  120. void idColorSpace::ConvertCoCgSYToRGB( byte * dst, const byte * src, int width, int height ) {
  121. for ( int i = 0; i < width * height; i++ ) {
  122. int co = src[i*4+0] - 128;
  123. int cg = src[i*4+1] - 128;
  124. int a = src[i*4+2];
  125. int y = src[i*4+3];
  126. float scale = 1.0f / ( 1.0f + a * ( 31.875f / 255.0f ) ) ;
  127. co = idMath::Ftoi( co * scale );
  128. cg = idMath::Ftoi( cg * scale );
  129. dst[i*4+0] = CLAMP_BYTE( y + COCG_TO_R( co, cg ) );
  130. dst[i*4+1] = CLAMP_BYTE( y + COCG_TO_G( co, cg ) );
  131. dst[i*4+2] = CLAMP_BYTE( y + COCG_TO_B( co, cg ) );
  132. dst[i*4+3] = 255;
  133. }
  134. }
  135. /*
  136. ========================
  137. idColorSpace::ConvertRGBToYCoCg420
  138. ========================
  139. */
  140. void idColorSpace::ConvertRGBToYCoCg420( byte *dst, const byte *src, int width, int height ) {
  141. int numSamples = 0;
  142. for ( int j = 0; j < height; j += 2 ) {
  143. for ( int i = 0; i < width; i += 2 ) {
  144. int r0 = src[((j+0)*width+i+0)*4+0];
  145. int g0 = src[((j+0)*width+i+0)*4+1];
  146. int b0 = src[((j+0)*width+i+0)*4+2];
  147. int r1 = src[((j+0)*width+i+1)*4+0];
  148. int g1 = src[((j+0)*width+i+1)*4+1];
  149. int b1 = src[((j+0)*width+i+1)*4+2];
  150. int r2 = src[((j+1)*width+i+0)*4+0];
  151. int g2 = src[((j+1)*width+i+0)*4+1];
  152. int b2 = src[((j+1)*width+i+0)*4+2];
  153. int r3 = src[((j+1)*width+i+1)*4+0];
  154. int g3 = src[((j+1)*width+i+1)*4+1];
  155. int b3 = src[((j+1)*width+i+1)*4+2];
  156. int y0 = CLAMP_BYTE( RGB_TO_YCOCG_Y( r0, g0, b0 ) );
  157. int co0 = CLAMP_BYTE( RGB_TO_YCOCG_CO( r0, g0, b0 ) + 128 );
  158. int cg0 = CLAMP_BYTE( RGB_TO_YCOCG_CG( r0, g0, b0 ) + 128 );
  159. int y1 = CLAMP_BYTE( RGB_TO_YCOCG_Y( r1, g1, b1 ) );
  160. int co1 = CLAMP_BYTE( RGB_TO_YCOCG_CO( r1, g1, b1 ) + 128 );
  161. int cg1 = CLAMP_BYTE( RGB_TO_YCOCG_CG( r1, g1, b1 ) + 128 );
  162. int y2 = CLAMP_BYTE( RGB_TO_YCOCG_Y( r2, g2, b2 ) );
  163. int co2 = CLAMP_BYTE( RGB_TO_YCOCG_CO( r2, g2, b2 ) + 128 );
  164. int cg2 = CLAMP_BYTE( RGB_TO_YCOCG_CG( r2, g2, b2 ) + 128 );
  165. int y3 = CLAMP_BYTE( RGB_TO_YCOCG_Y( r3, g3, b3 ) );
  166. int co3 = CLAMP_BYTE( RGB_TO_YCOCG_CO( r3, g3, b3 ) + 128 );
  167. int cg3 = CLAMP_BYTE( RGB_TO_YCOCG_CG( r3, g3, b3 ) + 128 );
  168. dst[numSamples+0] = y0;
  169. dst[numSamples+1] = y1;
  170. dst[numSamples+2] = y2;
  171. dst[numSamples+3] = y3;
  172. dst[numSamples+4] = ( co0 + co1 + co2 + co3 ) >> 2;
  173. dst[numSamples+5] = ( cg0 + cg1 + cg2 + cg3 ) >> 2;
  174. numSamples += 6;
  175. }
  176. numSamples += width;
  177. }
  178. }
  179. /*
  180. ========================
  181. idColorSpace::ConvertYCoCg420ToRGB
  182. ========================
  183. */
  184. void idColorSpace::ConvertYCoCg420ToRGB( byte *dst, const byte *src, int width, int height ) {
  185. int numSamples = width * height * 2 - width;
  186. for ( int j = height - 2; j >= 0; j -= 2 ) {
  187. for ( int i = width - 2; i >= 0; i -= 2 ) {
  188. int y0 = src[numSamples-6];
  189. int y1 = src[numSamples-5];
  190. int y2 = src[numSamples-4];
  191. int y3 = src[numSamples-3];
  192. int co = src[numSamples-2] - 128;
  193. int cg = src[numSamples-1] - 128;
  194. numSamples -= 6;
  195. int r = COCG_TO_R( co, cg );
  196. int g = COCG_TO_G( co, cg );
  197. int b = COCG_TO_B( co, cg );
  198. dst[((j+0)*width+i+0)*4+0] = CLAMP_BYTE( y0 + r );
  199. dst[((j+0)*width+i+0)*4+1] = CLAMP_BYTE( y0 + g );
  200. dst[((j+0)*width+i+0)*4+2] = CLAMP_BYTE( y0 + b );
  201. dst[((j+0)*width+i+1)*4+0] = CLAMP_BYTE( y1 + r );
  202. dst[((j+0)*width+i+1)*4+1] = CLAMP_BYTE( y1 + g );
  203. dst[((j+0)*width+i+1)*4+2] = CLAMP_BYTE( y1 + b );
  204. dst[((j+1)*width+i+0)*4+0] = CLAMP_BYTE( y2 + r );
  205. dst[((j+1)*width+i+0)*4+1] = CLAMP_BYTE( y2 + g );
  206. dst[((j+1)*width+i+0)*4+2] = CLAMP_BYTE( y2 + b );
  207. dst[((j+1)*width+i+1)*4+0] = CLAMP_BYTE( y3 + r );
  208. dst[((j+1)*width+i+1)*4+1] = CLAMP_BYTE( y3 + g );
  209. dst[((j+1)*width+i+1)*4+2] = CLAMP_BYTE( y3 + b );
  210. }
  211. numSamples -= width;
  212. }
  213. }
  214. /*
  215. ================================================================================================
  216. To *Color-Convert RGB and YCbCr* ColorSpaces, note that YCbCr is defined per
  217. CCIR 601-1, except that Cb and Cr are normalized to the range 0 -> 255 rather than -0.5 -> 0.5.
  218. The conversion equations to be implemented are therefore:
  219. Y = [ 0.29900 0.58700 0.11400] [R]
  220. Cb = [-0.16874 -0.33126 0.50000] [G] + 128
  221. Cr = [ 0.50000 -0.41869 -0.08131] [B] + 128
  222. R = [ 1.00000 0.00000 1.40200] [Y]
  223. G = [ 1.00000 -0.34414 -0.71414] [Cb - 128]
  224. B = [ 1.00000 1.77200 0.00000] [Cr - 128]
  225. These numbers are derived from TIFF 6.0 section 21, dated 3-June-92. To avoid floating-point
  226. arithmetic, we represent the fractional constants as integers scaled up by 2^16 (about 4 digits
  227. precision); we have to divide the products by 2^16, with appropriate rounding, to get the
  228. correct answer.
  229. ================================================================================================
  230. */
  231. const int ycbcr_shift = 16;
  232. const int ycbcr_round = 1 << ( ycbcr_shift - 1 );
  233. const int r029900 = 19595; // int( 0.29900 * (1<<16) + 0.5 )
  234. const int g058700 = 38470; // int( 0.58700 * (1<<16) + 0.5 )
  235. const int b011400 = 7471; // int( 0.11400 * (1<<16) + 0.5 )
  236. const int r016874 = 11059; // int( 0.16874 * (1<<16) + 0.5 )
  237. const int g033126 = 21709; // int( 0.33126 * (1<<16) + 0.5 )
  238. const int b050000 = 32768; // int( 0.50000 * (1<<16) + 0.5 )
  239. const int r050000 = 32768; // int( 0.50000 * (1<<16) + 0.5 )
  240. const int g041869 = 27439; // int( 0.41869 * (1<<16) + 0.5 )
  241. const int b008131 = 5329; // int( 0.08131 * (1<<16) + 0.5 )
  242. const int r140200 = 91881; // int( 1.40200 * (1<<16) + 0.5 )
  243. const int b177200 = 116130; // int( 1.77200 * (1<<16) + 0.5 )
  244. const int g071414 = 46802; // int( 0.71414 * (1<<16) + 0.5 )
  245. const int g034414 = 22554; // int( 0.34414 * (1<<16) + 0.5 )
  246. #define RGB_TO_YCBCR_Y( r, g, b ) ( ( ( r * r029900 + g * g058700 + b * b011400 ) + ycbcr_round ) >> ycbcr_shift )
  247. #define RGB_TO_YCBCR_CB( r, g, b ) ( ( ( - r * r016874 - g * g033126 + b * b050000 ) + ycbcr_round ) >> ycbcr_shift )
  248. #define RGB_TO_YCBCR_CR( r, g, b ) ( ( ( r * r050000 - g * g041869 - b * b008131 ) + ycbcr_round ) >> ycbcr_shift )
  249. #define CBCR_TO_R( cb, cr ) ( ( ycbcr_round + cr * r140200 ) >> ycbcr_shift )
  250. #define CBCR_TO_G( cb, cr ) ( ( ycbcr_round - cb * g034414 - cr * g071414 ) >> ycbcr_shift )
  251. #define CBCR_TO_B( cb, cr ) ( ( ycbcr_round + cb * b177200 ) >> ycbcr_shift )
  252. /*
  253. ========================
  254. idColorSpace::ConvertRGBToYCbCr
  255. ========================
  256. */
  257. void idColorSpace::ConvertRGBToYCbCr( byte *dst, const byte *src, int width, int height ) {
  258. for ( int i = 0; i < width * height; i++ ) {
  259. int r = src[i*4+0];
  260. int g = src[i*4+1];
  261. int b = src[i*4+2];
  262. int a = src[i*4+3];
  263. dst[i*4+0] = CLAMP_BYTE( RGB_TO_YCBCR_Y( r, g, b ) );
  264. dst[i*4+1] = CLAMP_BYTE( RGB_TO_YCBCR_CB( r, g, b ) + 128 );
  265. dst[i*4+2] = CLAMP_BYTE( RGB_TO_YCBCR_CR( r, g, b ) + 128 );
  266. dst[i*4+3] = a;
  267. }
  268. }
  269. /*
  270. ========================
  271. idColorSpace::ConvertYCbCrToRGB
  272. ========================
  273. */
  274. void idColorSpace::ConvertYCbCrToRGB( byte *dst, const byte *src, int width, int height ) {
  275. for ( int i = 0; i < width * height; i++ ) {
  276. int y = src[i*4+0];
  277. int cb = src[i*4+1] - 128;
  278. int cr = src[i*4+2] - 128;
  279. dst[i*4+0] = CLAMP_BYTE( y + CBCR_TO_R( cb, cr ) );
  280. dst[i*4+1] = CLAMP_BYTE( y + CBCR_TO_G( cb, cr ) );
  281. dst[i*4+2] = CLAMP_BYTE( y + CBCR_TO_B( cb, cr ) );
  282. }
  283. }
  284. /*
  285. ========================
  286. idColorSpace::ConvertRGBToCbCr_Y
  287. ========================
  288. */
  289. void idColorSpace::ConvertRGBToCbCr_Y( byte *dst, const byte *src, int width, int height ) {
  290. for ( int i = 0; i < width * height; i++ ) {
  291. int r = src[i*4+0];
  292. int g = src[i*4+1];
  293. int b = src[i*4+2];
  294. int a = src[i*4+3];
  295. dst[i*4+0] = CLAMP_BYTE( RGB_TO_YCBCR_CB( r, g, b ) + 128 );
  296. dst[i*4+1] = CLAMP_BYTE( RGB_TO_YCBCR_CR( r, g, b ) + 128 );
  297. dst[i*4+2] = a;
  298. dst[i*4+3] = CLAMP_BYTE( RGB_TO_YCBCR_Y( r, g, b ) );
  299. }
  300. }
  301. /*
  302. ========================
  303. idColorSpace::ConvertCbCr_YToRGB
  304. ========================
  305. */
  306. void idColorSpace::ConvertCbCr_YToRGB( byte *dst, const byte *src, int width, int height ) {
  307. for ( int i = 0; i < width * height; i++ ) {
  308. int cb = src[i*4+0] - 128;
  309. int cr = src[i*4+1] - 128;
  310. int a = src[i*4+2];
  311. int y = src[i*4+3];
  312. dst[i*4+0] = CLAMP_BYTE( y + CBCR_TO_R( cb, cr ) );
  313. dst[i*4+1] = CLAMP_BYTE( y + CBCR_TO_G( cb, cr ) );
  314. dst[i*4+2] = CLAMP_BYTE( y + CBCR_TO_B( cb, cr ) );
  315. dst[i*4+3] = a;
  316. }
  317. }
  318. /*
  319. ========================
  320. idColorSpace::ConvertRGBToYCbCr420
  321. ========================
  322. */
  323. void idColorSpace::ConvertRGBToYCbCr420( byte *dst, const byte *src, int width, int height ) {
  324. int numSamples = 0;
  325. for ( int j = 0; j < height; j += 2 ) {
  326. for ( int i = 0; i < width; i += 2 ) {
  327. int r0 = src[((j+0)*width+i+0)*4+0];
  328. int g0 = src[((j+0)*width+i+0)*4+1];
  329. int b0 = src[((j+0)*width+i+0)*4+2];
  330. int r1 = src[((j+0)*width+i+1)*4+0];
  331. int g1 = src[((j+0)*width+i+1)*4+1];
  332. int b1 = src[((j+0)*width+i+1)*4+2];
  333. int r2 = src[((j+1)*width+i+0)*4+0];
  334. int g2 = src[((j+1)*width+i+0)*4+1];
  335. int b2 = src[((j+1)*width+i+0)*4+2];
  336. int r3 = src[((j+1)*width+i+1)*4+0];
  337. int g3 = src[((j+1)*width+i+1)*4+1];
  338. int b3 = src[((j+1)*width+i+1)*4+2];
  339. int y0 = CLAMP_BYTE( RGB_TO_YCBCR_Y( r0, g0, b0 ) );
  340. int cb0 = CLAMP_BYTE( RGB_TO_YCBCR_CB( r0, g0, b0 ) + 128 );
  341. int cr0 = CLAMP_BYTE( RGB_TO_YCBCR_CR( r0, g0, b0 ) + 128 );
  342. int y1 = CLAMP_BYTE( RGB_TO_YCBCR_Y( r1, g1, b1 ) );
  343. int cb1 = CLAMP_BYTE( RGB_TO_YCBCR_CB( r1, g1, b1 ) + 128 );
  344. int cr1 = CLAMP_BYTE( RGB_TO_YCBCR_CR( r1, g1, b1 ) + 128 );
  345. int y2 = CLAMP_BYTE( RGB_TO_YCBCR_Y( r2, g2, b2 ) );
  346. int cb2 = CLAMP_BYTE( RGB_TO_YCBCR_CB( r2, g2, b2 ) + 128 );
  347. int cr2 = CLAMP_BYTE( RGB_TO_YCBCR_CR( r2, g2, b2 ) + 128 );
  348. int y3 = CLAMP_BYTE( RGB_TO_YCBCR_Y( r3, g3, b3 ) );
  349. int cb3 = CLAMP_BYTE( RGB_TO_YCBCR_CB( r3, g3, b3 ) + 128 );
  350. int cr3 = CLAMP_BYTE( RGB_TO_YCBCR_CR( r3, g3, b3 ) + 128 );
  351. dst[numSamples+0] = y0;
  352. dst[numSamples+1] = y1;
  353. dst[numSamples+2] = y2;
  354. dst[numSamples+3] = y3;
  355. dst[numSamples+4] = ( cb0 + cb1 + cb2 + cb3 ) >> 2;
  356. dst[numSamples+5] = ( cr0 + cr1 + cr2 + cr3 ) >> 2;
  357. numSamples += 6;
  358. }
  359. numSamples += width;
  360. }
  361. }
  362. /*
  363. ========================
  364. idColorSpace::ConvertYCbCr420ToRGB
  365. ========================
  366. */
  367. void idColorSpace::ConvertYCbCr420ToRGB( byte *dst, const byte *src, int width, int height ) {
  368. int numSamples = width * height * 2 - width;
  369. for ( int j = height - 2; j >= 0; j -= 2 ) {
  370. for ( int i = width - 2; i >= 0; i -= 2 ) {
  371. int y0 = src[numSamples-6];
  372. int y1 = src[numSamples-5];
  373. int y2 = src[numSamples-4];
  374. int y3 = src[numSamples-3];
  375. int co = src[numSamples-2] - 128;
  376. int cg = src[numSamples-1] - 128;
  377. numSamples -= 6;
  378. int r = CBCR_TO_R( co, cg );
  379. int g = CBCR_TO_G( co, cg );
  380. int b = CBCR_TO_B( co, cg );
  381. dst[((j+0)*width+i+0)*4+0] = CLAMP_BYTE( y0 + r );
  382. dst[((j+0)*width+i+0)*4+1] = CLAMP_BYTE( y0 + g );
  383. dst[((j+0)*width+i+0)*4+2] = CLAMP_BYTE( y0 + b );
  384. dst[((j+0)*width+i+1)*4+0] = CLAMP_BYTE( y1 + r );
  385. dst[((j+0)*width+i+1)*4+1] = CLAMP_BYTE( y1 + g );
  386. dst[((j+0)*width+i+1)*4+2] = CLAMP_BYTE( y1 + b );
  387. dst[((j+1)*width+i+0)*4+0] = CLAMP_BYTE( y2 + r );
  388. dst[((j+1)*width+i+0)*4+1] = CLAMP_BYTE( y2 + g );
  389. dst[((j+1)*width+i+0)*4+2] = CLAMP_BYTE( y2 + b );
  390. dst[((j+1)*width+i+1)*4+0] = CLAMP_BYTE( y3 + r );
  391. dst[((j+1)*width+i+1)*4+1] = CLAMP_BYTE( y3 + g );
  392. dst[((j+1)*width+i+1)*4+2] = CLAMP_BYTE( y3 + b );
  393. }
  394. numSamples -= width;
  395. }
  396. }
  397. /*
  398. ========================
  399. idColorSpace::ConvertNormalMapToStereographicHeightMap
  400. Converts a tangent space normal map to a height map.
  401. The iterative algorithm is pretty crappy but it's reasonably fast and good enough for testing purposes.
  402. The algorithm uses a stereographic projection of the normals to reduce the entropy and preserve
  403. significantly more detail.
  404. A better approach would be to solve the massive but rather sparse matrix system:
  405. [ c(1,0) c(1,1) ... c(1,w*h) ] [ H(1,1) ] [ Nx(1,1) ]
  406. [ c(2,0) c(2,1) ... c(2,w*h) ] [ H(1,2) ] = [ Ny(1,1) ]
  407. [ ... ] [ ... ] [ ... ]
  408. [ ... ] [ H(w,h) ] [ Nx(w,h) ]
  409. [ c(w*h*2,0) c(w*h*2,1) ... c(w*h*2,w*h)] [ Ny(w,h) ]
  410. Where: w = width, h = height, H(i,j) = height, Nx(i,j) = (normal.x/(1+normal.z), Ny(i,j) = (normal.y/(1+normal.z)
  411. The c(i,j) are setup such that:
  412. Nx(i,j) = H(i,j) - H(i,j+1)
  413. Ny(i,j) = H(i,j) - H(i+1,j)
  414. Nx(i,w) = H(i,w)
  415. Ny(h,j) = H(h,j)
  416. ========================
  417. */
  418. void idColorSpace::ConvertNormalMapToStereographicHeightMap( byte *heightMap, const byte *normalMap, int width, int height, float &scale ) {
  419. idTempArray<float> buffer( (width+1) * (height+1) * sizeof( float ) );
  420. float * temp = (float *)buffer.Ptr();
  421. memset( temp, 0, (width+1) * (height+1) * sizeof( float ) );
  422. const int NUM_ITERATIONS = 32;
  423. float scale0 = 0.1f;
  424. float scale1 = 0.9f;
  425. for ( int n = 0; n < NUM_ITERATIONS; n++ ) {
  426. for ( int i = 0; i < height; i++ ) {
  427. for ( int j = 1; j < width; j++ ) {
  428. float x = NORMALMAP_BYTE_TO_FLOAT( normalMap[( (i+0) * width + (j+0) ) * 4 + 0] );
  429. float z = NORMALMAP_BYTE_TO_FLOAT( normalMap[( (i+0) * width + (j+0) ) * 4 + 2] );
  430. temp[i * width + j] = scale0 * temp[i * width + j] + scale1 * ( temp[(i+0) * width + (j-1)] - ( x / (1+z) ) );
  431. }
  432. }
  433. for ( int i = 1; i < height; i++ ) {
  434. for ( int j = 0; j < width; j++ ) {
  435. float y = NORMALMAP_BYTE_TO_FLOAT( normalMap[( (i+0) * width + (j+0) ) * 4 + 1] );
  436. float z = NORMALMAP_BYTE_TO_FLOAT( normalMap[( (i+0) * width + (j+0) ) * 4 + 2] );
  437. temp[i * width + j] = scale0 * temp[i * width + j] + scale1 * ( temp[(i-1) * width + (j+0)] - ( y / (1+z)) );
  438. }
  439. }
  440. for ( int i = 0; i < height; i++ ) {
  441. for ( int j = width - 1; j > 0; j-- ) {
  442. float x = NORMALMAP_BYTE_TO_FLOAT( normalMap[( (i+0) * width + (j-1) ) * 4 + 0] );
  443. float z = NORMALMAP_BYTE_TO_FLOAT( normalMap[( (i+0) * width + (j-1) ) * 4 + 2] );
  444. temp[i * width + (j-1)] = scale0 * temp[i * width + (j-1)] + scale1 * ( temp[(i+0) * width + (j+0)] + ( x / (1+z) ) );
  445. }
  446. }
  447. for ( int i = height - 1; i > 0; i-- ) {
  448. for ( int j = 0; j < width; j++ ) {
  449. float y = NORMALMAP_BYTE_TO_FLOAT( normalMap[( (i-1) * width + (j+0) ) * 4 + 1] );
  450. float z = NORMALMAP_BYTE_TO_FLOAT( normalMap[( (i-1) * width + (j+0) ) * 4 + 2] );
  451. temp[(i-1) * width + j] = scale0 * temp[(i-1) * width + j] + scale1 * ( temp[(i+0) * width + (j+0)] + ( y / (1+z) ) );
  452. }
  453. }
  454. scale1 *= 0.99f;
  455. scale0 = 1.0f - scale1;
  456. }
  457. float minHeight = idMath::INFINITY;
  458. float maxHeight = -idMath::INFINITY;
  459. for ( int j = 0; j < height; j++ ) {
  460. for ( int i = 0; i < width; i++ ) {
  461. if ( temp[j*width+i] < minHeight ) {
  462. minHeight = temp[j*width+i];
  463. }
  464. if ( temp[j*width+i] > maxHeight ) {
  465. maxHeight = temp[j*width+i];
  466. }
  467. }
  468. }
  469. scale = ( maxHeight - minHeight );
  470. float s = 255.0f / scale;
  471. for ( int j = 0; j < height; j++ ) {
  472. for ( int i = 0; i < width; i++ ) {
  473. heightMap[j*width+i] = idMath::Ftob( ( temp[j*width+i] - minHeight ) * s );
  474. }
  475. }
  476. }
  477. /*
  478. ========================
  479. idColorSpace::ConvertStereographicHeightMapToNormalMap
  480. This converts a heightmap of a stereographically projected normal map back into a regular normal map.
  481. ========================
  482. */
  483. void idColorSpace::ConvertStereographicHeightMapToNormalMap( byte *normalMap, const byte *heightMap, int width, int height, float scale ) {
  484. for ( int i = 0; i < height; i++ ) {
  485. int previ = Max( i, 0 );
  486. int nexti = Min( i + 1, height - 1 );
  487. for ( int j = 0; j < width; j++ ) {
  488. int prevj = Max( j, 0 );
  489. int nextj = Min( j + 1, width - 1 );
  490. idVec3 normal;
  491. float pX = scale * ( heightMap[i * width + prevj] - heightMap[i * width + nextj] ) / 255.0f;
  492. float pY = scale * ( heightMap[previ * width + j] - heightMap[nexti * width + j] ) / 255.0f;
  493. float denom = 2.0f / ( 1.0f + pX * pX + pY * pY );
  494. normal.x = pX * denom;
  495. normal.y = pY * denom;
  496. normal.z = denom - 1.0f;
  497. normalMap[ ( i * width + j ) * 4 + 0 ] = NORMALMAP_FLOAT_TO_BYTE( normal[0] );
  498. normalMap[ ( i * width + j ) * 4 + 1 ] = NORMALMAP_FLOAT_TO_BYTE( normal[1] );
  499. normalMap[ ( i * width + j ) * 4 + 2 ] = NORMALMAP_FLOAT_TO_BYTE( normal[2] );
  500. normalMap[ ( i * width + j ) * 4 + 3 ] = 255;
  501. }
  502. }
  503. }
  504. /*
  505. ========================
  506. idColorSpace::ConvertRGBToMonochrome
  507. ========================
  508. */
  509. void idColorSpace::ConvertRGBToMonochrome( byte *mono, const byte *rgb, int width, int height ) {
  510. for ( int i = 0; i < height; i++ ) {
  511. for ( int j = 0; j < width; j++ ) {
  512. mono[i * width + j] = ( rgb[( i * width + j ) * 4 + 0] +
  513. rgb[( i * width + j ) * 4 + 1] +
  514. rgb[( i * width + j ) * 4 + 2] ) / 3;
  515. }
  516. }
  517. }
  518. /*
  519. ========================
  520. idColorSpace::ConvertMonochromeToRGB
  521. ========================
  522. */
  523. void idColorSpace::ConvertMonochromeToRGB( byte *rgb, const byte *mono, int width, int height ) {
  524. for ( int i = 0; i < height; i++ ) {
  525. for ( int j = 0; j < width; j++ ) {
  526. rgb[( i * width + j ) * 4 + 0] = mono[i * width + j];
  527. rgb[( i * width + j ) * 4 + 1] = mono[i * width + j];
  528. rgb[( i * width + j ) * 4 + 2] = mono[i * width + j];
  529. }
  530. }
  531. }