compositor for 2d glitch effects
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

effects.pde 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500
  1. /*
  2. ASDFPIXELSORT
  3. */
  4. class ASDFPIXELSORT extends Shader {
  5. ASDFPIXELSORT() {
  6. name = "fxASDFPixelSort";
  7. params.add(new Param("black", INTVAL, -17000000, -2000000, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  8. params.add(new Param("target", INTVAL, 0, 2, new int[]{RANDOM}));
  9. }
  10. int previousMode;
  11. void apply() {
  12. if (previousMode != int(params.get(1).value)) {
  13. if (params.get(1).value == 0) changeParam(0, new Param("black", INTVAL, -17000000, -2000000, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  14. if (params.get(1).value == 1) changeParam(0, new Param("brightness", INTVAL, 0, 200, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  15. if (params.get(1).value == 2) changeParam(0, new Param("white", INTVAL, -15000000, -700000, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  16. }
  17. previousMode = int(params.get(1).value);
  18. row = 0;
  19. column = 0;
  20. renderer.beginDraw();
  21. renderer.colorMode(RGB);
  22. colorMode(RGB);
  23. while (column < renderer.width-1) {
  24. renderer.loadPixels();
  25. sortColumn();
  26. column++;
  27. renderer.updatePixels();
  28. }
  29. while (row < renderer.height-1) {
  30. renderer.loadPixels();
  31. sortRow();
  32. row++;
  33. renderer.updatePixels();
  34. }
  35. renderer.endDraw();
  36. }
  37. int row = 0;
  38. int column = 0;
  39. void sortRow() {
  40. int x = 0;
  41. int y = row;
  42. int xend = 0;
  43. while (xend < renderer.width-1) {
  44. switch((int)params.get(1).value) {
  45. case 0:
  46. x = getFirstNotBlackX(x, y);
  47. xend = getNextBlackX(x, y);
  48. break;
  49. case 1:
  50. x = getFirstBrightX(x, y);
  51. xend = getNextDarkX(x, y);
  52. break;
  53. case 2:
  54. x = getFirstNotWhiteX(x, y);
  55. xend = getNextWhiteX(x, y);
  56. break;
  57. default:
  58. break;
  59. }
  60. if (x < 0) break;
  61. int sortLength = xend-x;
  62. color[] unsorted = new color[sortLength];
  63. color[] sorted = new color[sortLength];
  64. for (int i=0; i<sortLength; i++) {
  65. unsorted[i] = renderer.pixels[x + i + y * renderer.width];
  66. }
  67. sorted = sort(unsorted);
  68. for (int i=0; i<sortLength; i++) {
  69. renderer.pixels[x + i + y * renderer.width] = sorted[i];
  70. }
  71. x = xend+1;
  72. }
  73. }
  74. void sortColumn() {
  75. int x = column;
  76. int y = 0;
  77. int yend = 0;
  78. while (yend < renderer.height-1) {
  79. switch((int)params.get(1).value) {
  80. case 0:
  81. y = getFirstNotBlackY(x, y);
  82. yend = getNextBlackY(x, y);
  83. break;
  84. case 1:
  85. y = getFirstBrightY(x, y);
  86. yend = getNextDarkY(x, y);
  87. break;
  88. case 2:
  89. y = getFirstNotWhiteY(x, y);
  90. yend = getNextWhiteY(x, y);
  91. break;
  92. default:
  93. break;
  94. }
  95. if (y < 0) break;
  96. int sortLength = yend-y;
  97. color[] unsorted = new color[sortLength];
  98. color[] sorted = new color[sortLength];
  99. for (int i=0; i<sortLength; i++) {
  100. unsorted[i] = renderer.pixels[x + (y+i) * renderer.width];
  101. }
  102. sorted = sort(unsorted);
  103. for (int i=0; i<sortLength; i++) {
  104. renderer.pixels[x + (y+i) * renderer.width] = sorted[i];
  105. }
  106. y = yend+1;
  107. }
  108. }
  109. //BLACK
  110. int getFirstNotBlackX(int _x, int _y) {
  111. int x = _x;
  112. int y = _y;
  113. color c;
  114. while ( (c = renderer.pixels[x + y * renderer.width]) < params.get(0).value) {
  115. x++;
  116. if (x >= renderer.width) return -1;
  117. }
  118. return x;
  119. }
  120. int getNextBlackX(int _x, int _y) {
  121. int x = _x+1;
  122. int y = _y;
  123. color c;
  124. while ( (c = renderer.pixels[x + y * renderer.width]) > params.get(0).value) {
  125. x++;
  126. if (x >= renderer.width) return renderer.width-1;
  127. }
  128. return x-1;
  129. }
  130. //BRIGHTNESS
  131. int getFirstBrightX(int _x, int _y) {
  132. int x = _x;
  133. int y = _y;
  134. color c;
  135. while (brightness (c = renderer.pixels[x + y * renderer.width]) < params.get(0).value) {
  136. x++;
  137. if (x >= renderer.width) return -1;
  138. }
  139. return x;
  140. }
  141. int getNextDarkX(int _x, int _y) {
  142. int x = _x+1;
  143. int y = _y;
  144. color c;
  145. while (brightness (c = renderer.pixels[x + y * renderer.width]) > params.get(0).value) {
  146. x++;
  147. if (x >= renderer.width) return renderer.width-1;
  148. }
  149. return x-1;
  150. }
  151. //WHITE
  152. int getFirstNotWhiteX(int _x, int _y) {
  153. int x = _x;
  154. int y = _y;
  155. color c;
  156. while ( (c = renderer.pixels[x + y * renderer.width]) > params.get(0).value) {
  157. x++;
  158. if (x >= renderer.width) return -1;
  159. }
  160. return x;
  161. }
  162. int getNextWhiteX(int _x, int _y) {
  163. int x = _x+1;
  164. int y = _y;
  165. color c;
  166. while ( (c = renderer.pixels[x + y * renderer.width]) < params.get(0).value) {
  167. x++;
  168. if (x >= renderer.width) return renderer.width-1;
  169. }
  170. return x-1;
  171. }
  172. //BLACK
  173. int getFirstNotBlackY(int _x, int _y) {
  174. int x = _x;
  175. int y = _y;
  176. color c;
  177. if (y < renderer.height) {
  178. while ( (c = renderer.pixels[x + y * renderer.width]) < params.get(0).value) {
  179. y++;
  180. if (y >= renderer.height) return -1;
  181. }
  182. }
  183. return y;
  184. }
  185. int getNextBlackY(int _x, int _y) {
  186. int x = _x;
  187. int y = _y+1;
  188. color c;
  189. if (y < renderer.height) {
  190. while ( (c = renderer.pixels[x + y * renderer.width]) > params.get(0).value) {
  191. y++;
  192. if (y >= renderer.height) return renderer.height-1;
  193. }
  194. }
  195. return y-1;
  196. }
  197. //BRIGHTNESS
  198. int getFirstBrightY(int _x, int _y) {
  199. int x = _x;
  200. int y = _y;
  201. color c;
  202. if (y < renderer.height) {
  203. while (brightness (c = renderer.pixels[x + y * renderer.width]) < params.get(0).value) {
  204. y++;
  205. if (y >= renderer.height) return -1;
  206. }
  207. }
  208. return y;
  209. }
  210. int getNextDarkY(int _x, int _y) {
  211. int x = _x;
  212. int y = _y+1;
  213. color c;
  214. if (y < renderer.height) {
  215. while (brightness (c = renderer.pixels[x + y * renderer.width]) > params.get(0).value) {
  216. y++;
  217. if (y >= renderer.height) return renderer.height-1;
  218. }
  219. }
  220. return y-1;
  221. }
  222. //WHITE
  223. int getFirstNotWhiteY(int _x, int _y) {
  224. int x = _x;
  225. int y = _y;
  226. color c;
  227. if (y < renderer.height) {
  228. while ( (c = renderer.pixels[x + y * renderer.width]) > params.get(0).value) {
  229. y++;
  230. if (y >= renderer.height) return -1;
  231. }
  232. }
  233. return y;
  234. }
  235. int getNextWhiteY(int _x, int _y) {
  236. int x = _x;
  237. int y = _y+1;
  238. color c;
  239. if (y < renderer.height) {
  240. while ( (c = renderer.pixels[x + y * renderer.width]) < params.get(0).value) {
  241. y++;
  242. if (y >= renderer.height) return renderer.height-1;
  243. }
  244. }
  245. return y-1;
  246. }
  247. }
  248. /*
  249. DISTORTER
  250. */
  251. class DISTORTER extends Shader {
  252. boolean do_blend = false; // blend image after process
  253. int blend_mode = OVERLAY; // blend type
  254. int channel = BRIGHTNESS; // channel used in processing (R,G,B) or (H,S,B)
  255. float scalex = 0.05; // from 0.01 to 1
  256. float scaley = 0.1; // from 0.01 to 1
  257. boolean shift_hue = true;
  258. float shift_amt = 0.1; // from 0 to 1
  259. PImage buffer;
  260. int[][] distort = new int[2][512];
  261. final static float tick = 1.0/512.0;
  262. int mode = 0;
  263. DISTORTER() {
  264. buffer = createImage(renderer.width, renderer.height, ARGB);
  265. name = "fxDistorter";
  266. params.add(new Param("width", FLOATVAL, 2, buffer.width/4-1, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  267. params.add(new Param("height", FLOATVAL, 2, buffer.height/4-1, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  268. params.add(new Param("do blend", INTVAL, 0, 1, new int[]{RANDOM, SQUAR}));
  269. params.add(new Param("shift hue amount", FLOATVAL, 0, 1, new int[]{SAWTOOTH, SAWTOOTHINVERSE, TAN, TANINVERSE, RAMP, RAMPINVERSE}));
  270. params.add(new Param("scale x", FLOATVAL, 0.01, 1, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  271. params.add(new Param("scale y", FLOATVAL, 0.01, 1, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  272. params.add(new Param("blend mode", INTVAL, 0, blends.length-1, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  273. params.add(new Param("channel", INTVAL, 0, 12, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  274. // channel, blend_mode
  275. //params.add(new Param("height", FLOATVAL, 1, buffer.height/4-1, new int[]{SINE, SAWTOOTH, RAMPUPDOWN, TAN, TANINVERSE, TRIANG}));
  276. // prepare distortion pattern
  277. for (int i=0; i<512; i++) {
  278. distort[0][i] = (int)random(-128, 128);
  279. distort[1][i] = (int)random(-128, 128);
  280. }
  281. }
  282. // ALL Channels, Nxxx stand for negative (255-value)
  283. // channels to work with
  284. final static int RED = 0;
  285. final static int GREEN = 1;
  286. final static int BLUE = 2;
  287. final static int HUE = 3;
  288. final static int SATURATION = 4;
  289. final static int BRIGHTNESS = 5;
  290. final static int NRED = 6;
  291. final static int NGREEN = 7;
  292. final static int NBLUE = 8;
  293. final static int NHUE = 9;
  294. final static int NSATURATION = 10;
  295. final static int NBRIGHTNESS = 11;
  296. void apply() {
  297. println(buffer.height);
  298. buffer = renderer.get();
  299. buffer.resize(renderer.width, renderer.height);
  300. float neww = params.get(0).value;
  301. float newh = params.get(1).value;
  302. do_blend = boolean(int(params.get(2).value));
  303. shift_amt = params.get(3).value;
  304. scalex = params.get(4).value;
  305. scaley = params.get(5).value;
  306. blend_mode = blends[(int)params.get(6).value];
  307. channel = (int)params.get(7).value;
  308. float totalnum = neww+newh;
  309. float times = (totalnum/floor(totalnum/neww));
  310. float offx = (totalnum%neww)/times;
  311. float ratiox = neww/buffer.width;
  312. println(ratiox);
  313. renderer.beginDraw();
  314. renderer.noStroke();
  315. for (int y=0; y<buffer.height; y++) {
  316. float yy = y/(float)buffer.height;
  317. for (int x=0; x<buffer.width; x++) {
  318. float xx = x/(float)buffer.width;
  319. float offy = floor(newh*yy);
  320. float fx = xx*ratiox+offx*offy;
  321. float shift = fx%1.0;
  322. float st = shift/tick;
  323. int no1 = floor(st)%512;
  324. int no2 = ceil(st)%512;
  325. float l = st-(float)no1;
  326. float cx = lerp(distort[0][no1], distort[0][no2], l);
  327. float cy = lerp(distort[1][no1], distort[1][no2], l);
  328. float rx =getChannel(buffer.get(x, y), channel);
  329. int sx = (int)((buffer.width+x+cx*rx*scalex*0.1)%buffer.width);
  330. int sy = (int)((buffer.height+y+cy*scaley)%buffer.height);
  331. color c=buffer.get(sx, sy);
  332. if (shift_hue) {
  333. colorMode(HSB, 255);
  334. c = color((hue(c)+shift_amt*255*noise(newh+y))%255.0, constrain(saturation(c)*1.2, 0, 255), constrain(brightness(c), 0, 255));
  335. colorMode(RGB, 255);
  336. }
  337. // buffer.fill(lerpColor(c,img.get(x,y),0.2));
  338. renderer.fill(c); //wärs nich effizienter die pixelmatrix zu ändern ?
  339. renderer.rect(x, y, 1, 1);
  340. }
  341. }
  342. if (do_blend)
  343. renderer.blend(buffer, 0, 0, buffer.width, buffer.height, 0, 0, renderer.width, renderer.height, blend_mode);
  344. renderer.endDraw();
  345. }
  346. float getChannel(color c, int channel) {
  347. int ch = channel>5?channel-6:channel;
  348. float cc;
  349. switch(ch) {
  350. case RED:
  351. cc = red(c);
  352. break;
  353. case GREEN:
  354. cc = green(c);
  355. break;
  356. case BLUE:
  357. cc = blue(c);
  358. break;
  359. case HUE:
  360. cc = hue(c);
  361. break;
  362. case SATURATION:
  363. cc = saturation(c);
  364. break;
  365. default:
  366. cc= brightness(c);
  367. break;
  368. }
  369. return channel>5?255-cc:cc;
  370. }
  371. }
  372. /*
  373. FM
  374. */
  375. class FM extends Shader {
  376. // configuration
  377. int colorspace = RGB;
  378. int quantval = 30; // 0 - off, less - more glitch, more - more precision
  379. boolean do_blend = true; // blend image after process
  380. int blend_mode = OVERLAY; // blend type
  381. //unused parameters (giers):
  382. final static boolean first_channel_only = false; // for L.. or Y.. colorspaces set true to modulate only luma;
  383. final static boolean lowpass1_on = true; // on/off of first low pass filter
  384. final static boolean lowpass2_on = true; // on/off of second low pass filter
  385. final static boolean lowpass3_on = true; // on/off of third low pass filter
  386. // better don't touch it, lowpass filters are run in cascade
  387. float lowpass1_cutoff = 0.25; // percentage of rate
  388. float lowpass2_cutoff = 0.1;
  389. float lowpass3_cutoff = 0.05;
  390. // working buffer
  391. PGraphics buffer;
  392. // local variables
  393. float min_omega, max_omega;
  394. float min_phase_mult=0.05;
  395. float max_phase_mult=50.0;
  396. LowpassFilter lpf1, lpf2, lpf3;
  397. int[][] pxls;
  398. boolean negate = false;
  399. FM() {
  400. name = "fxFM";
  401. params.add(new Param("do blend", INTVAL, 0, 1, new int[]{RANDOM, SQUAR}));
  402. params.add(new Param ("blend_mode", INTVAL, 0, blends.length-1, new int[]{RANDOM}));
  403. params.add(new Param ("omega", FLOATVAL, 0, 1, new int[]{SINE, SAWTOOTH, TRIANG}));
  404. params.add(new Param ("phase", FLOATVAL, 0, 1, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE}));
  405. params.add(new Param ("colorspace", INTVAL, 0, 16, new int[]{RANDOM}));
  406. params.add(new Param ("quant", INTVAL, 0, 40, new int[]{SAWTOOTH, TRIANG, SINE, TAN, TANINVERSE, RAMPUPDOWN, RAMP, RAMPINVERSE}));
  407. buffer = createGraphics(renderer.width, renderer.height);
  408. buffer.beginDraw();
  409. buffer.noStroke();
  410. //buffer.smooth(8);
  411. //buffer.background(0);
  412. // buffer.image(renderer, 0, 0);
  413. buffer.endDraw();
  414. //img.loadPixels();
  415. min_omega = TWO_PI/(0.05*renderer.width);
  416. max_omega = TWO_PI/(300.0*renderer.width);
  417. float rate = 100000.0;
  418. lpf1 = new LowpassFilter(rate, lowpass1_cutoff*rate);
  419. lpf2 = new LowpassFilter(rate, lowpass2_cutoff*rate);
  420. lpf3 = new LowpassFilter(rate, lowpass3_cutoff*rate);
  421. rw = renderer.width;
  422. prepareData();
  423. }
  424. void prepareData() {
  425. pxls = new int[3][renderer.pixels.length];
  426. for (int i=0; i<renderer.pixels.length; i++) {
  427. int cl = toColorspace(renderer.pixels[i], colorspace);
  428. pxls[0][i] = (cl >> 16) & 0xff;
  429. pxls[1][i] = (cl >> 8) & 0xff;
  430. pxls[2][i] = (cl) & 0xff;
  431. }
  432. }
  433. float omega, min_phase, max_phase;
  434. int rw, rh;
  435. void apply() {
  436. do_blend = boolean(int(params.get(0).value));
  437. blend_mode = blends[(int)params.get(1).value];
  438. omega = map(sqrt(params.get(2).value), 0, 1, min_omega, max_omega);
  439. float phase = map(sq(params.get(3).value), 0, 1, min_phase_mult, max_phase_mult);
  440. colorspace = (int)params.get(4).value;
  441. quantval = (int) params.get(5).value;
  442. if (rw != renderer.width || rh != renderer.height) {
  443. rw = renderer.width;
  444. rh = renderer.height;
  445. min_omega = TWO_PI/(0.05*renderer.width);
  446. max_omega = TWO_PI/(300.0*renderer.width);
  447. prepareData();
  448. }
  449. buffer.setSize(renderer.width, renderer.height);
  450. max_phase = phase * omega;
  451. min_phase = -max_phase;
  452. processImage();
  453. }
  454. void processImage() {
  455. buffer.beginDraw();
  456. buffer.loadPixels();
  457. int [][] dest_pxls = new int[3][renderer.pixels.length];
  458. if (first_channel_only) {
  459. arrayCopy(pxls[1], dest_pxls[1]);
  460. arrayCopy(pxls[2], dest_pxls[2]);
  461. }
  462. for (int i=0; i< (first_channel_only?1:3); i++) {
  463. for (int y=0; y<renderer.height; y++) {
  464. int off = y * renderer.width;
  465. //reset filters each line
  466. lpf1.resetFilter(map(pxls[i][off], 0, 255, min_phase, max_phase));
  467. lpf2.resetFilter(map(pxls[i][off], 0, 255, min_phase, max_phase));
  468. lpf3.resetFilter(map(pxls[i][off], 0, 255, min_phase, max_phase));
  469. float sig_int = 0; // integral of the signal
  470. float pre_m = 0; // previous value of modulated signal
  471. for (int x=0; x<renderer.width; x++) {
  472. /////////////////////////
  473. // FM part starts here
  474. /////////////////////////
  475. float sig = map(pxls[i][x+off], 0, 255, min_phase, max_phase); // current signal value
  476. sig_int += sig; // current value of signal integral
  477. float m = cos(omega * x + sig_int); // modulate signal
  478. if ( quantval > 0) {
  479. m = map((int)map(m, -1, 1, 0, quantval), 0, quantval, -1, 1); // quantize
  480. }
  481. float dem = abs(m-pre_m); // demodulate signal, derivative
  482. pre_m = m; // remember current value
  483. // lowpass filter chain
  484. if (lowpass1_on) dem = lpf1.lowpass(dem);
  485. if (lowpass2_on) dem = lpf2.lowpass(dem);
  486. if (lowpass3_on) dem = lpf3.lowpass(dem);
  487. // remap signal back to channel value
  488. int v = constrain( (int)map(2*(dem-omega), min_phase, max_phase, 0, 255), 0, 255);
  489. //////////////////////
  490. // FM part ends here
  491. //////////////////////
  492. dest_pxls[i][x+off] = negate?255-v:v;
  493. }
  494. }
  495. }
  496. for (int i=0; i<buffer.pixels.length; i++) {
  497. buffer.pixels[i] = fromColorspace(0xff000000 | (dest_pxls[0][i] << 16) | (dest_pxls[1][i] << 8) | (dest_pxls[2][i]), colorspace);
  498. }
  499. buffer.updatePixels();
  500. if (do_blend)
  501. buffer.blend(renderer, 0, 0, renderer.width, renderer.height, 0, 0, buffer.width, buffer.height, blend_mode);
  502. buffer.endDraw();
  503. renderer.beginDraw();
  504. renderer.image(buffer, 0, 0, renderer.width, renderer.height);
  505. renderer.endDraw();
  506. }
  507. //
  508. final int[] blends = {
  509. ADD, SUBTRACT, DARKEST, LIGHTEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN
  510. };
  511. class LowpassFilter {
  512. float alpha;
  513. float prev;
  514. public LowpassFilter(float rate, float hz) {
  515. alpha = 0.0;
  516. prev = 0.0;
  517. setFilter(rate, hz);
  518. }
  519. void setFilter(float rate, float hz) {
  520. float timeInterval = 1.0/rate;
  521. float tau = 1.0 / (hz * TWO_PI);
  522. alpha = timeInterval / (tau + timeInterval);
  523. }
  524. void resetFilter(float val) {
  525. prev = val;
  526. }
  527. void resetFilter() {
  528. resetFilter(0);
  529. }
  530. float lowpass(float sample) {
  531. float stage1 = sample * alpha;
  532. float stage2 = prev - (prev * alpha);
  533. prev = (stage1 + stage2);
  534. return prev;
  535. }
  536. float highpass(float sample) {
  537. return sample - lowpass(sample);
  538. }
  539. }
  540. }
  541. // name
  542. String getColorspaceName(int cs) {
  543. switch(cs) {
  544. case OHTA:
  545. return "OHTA";
  546. case CMY:
  547. return "CMY";
  548. case XYZ:
  549. return "XYZ";
  550. case YXY:
  551. return "YXY";
  552. case HCL:
  553. return "HCL";
  554. case LUV:
  555. return "LUV";
  556. case LAB:
  557. return "LAB";
  558. case HWB:
  559. return "HWB";
  560. case HSB:
  561. return "HSB";
  562. case RGGBG:
  563. return "R-GGB-G";
  564. case YPbPr:
  565. return "YPbPr";
  566. case YCbCr:
  567. return "YCbCr";
  568. case YDbDr:
  569. return "YDbDr";
  570. case GS:
  571. return "Greyscale";
  572. case YUV:
  573. return "YUV";
  574. default:
  575. return "RGB";
  576. }
  577. }
  578. // colorspace converters
  579. color fromColorspace(color c, int cs) {
  580. switch(cs) {
  581. case OHTA:
  582. return fromOHTA(c);
  583. case CMY:
  584. return fromCMY(c);
  585. case XYZ:
  586. return fromXYZ(c);
  587. case YXY:
  588. return fromYXY(c);
  589. case HCL:
  590. return fromHCL(c);
  591. case LUV:
  592. return fromLUV(c);
  593. case LAB:
  594. return fromLAB(c);
  595. case HWB:
  596. return fromHWB(c);
  597. case HSB:
  598. return fromHSB(c);
  599. case RGGBG:
  600. return fromRGGBG(c);
  601. case YPbPr:
  602. return fromYPbPr(c);
  603. case YCbCr:
  604. return fromYCbCr(c);
  605. case YDbDr:
  606. return fromYDbDr(c);
  607. case GS:
  608. return tofromGS(c);
  609. case YUV:
  610. return fromYUV(c);
  611. default:
  612. return c;
  613. }
  614. }
  615. color toColorspace(color c, int cs) {
  616. switch(cs) {
  617. case OHTA:
  618. return toOHTA(c);
  619. case CMY:
  620. return toCMY(c);
  621. case XYZ:
  622. return toXYZ(c);
  623. case YXY:
  624. return toYXY(c);
  625. case HCL:
  626. return toHCL(c);
  627. case LUV:
  628. return toLUV(c);
  629. case LAB:
  630. return toLAB(c);
  631. case HWB:
  632. return toHWB(c);
  633. case HSB:
  634. return toHSB(c);
  635. case RGGBG:
  636. return toRGGBG(c);
  637. case YPbPr:
  638. return toYPbPr(c);
  639. case YCbCr:
  640. return toYCbCr(c);
  641. case YDbDr:
  642. return toYDbDr(c);
  643. case YUV:
  644. return toYUV(c);
  645. case GS:
  646. return tofromGS(c);
  647. default:
  648. return c;
  649. }
  650. }
  651. // Colorspace converters
  652. final int getR(color c) {
  653. return (c & 0xff0000) >> 16;
  654. }
  655. final int getG(color c) {
  656. return (c & 0xff00) >> 8;
  657. }
  658. final int getB(color c) {
  659. return c & 0xff;
  660. }
  661. final int getLuma(color c) {
  662. return constrain((int)(0.2126*getR(c)+0.7152*getG(c)+0.0722*getB(c)), 0, 255);
  663. }
  664. int getChannel(color c, int ch) {
  665. switch(ch) {
  666. case 0 :
  667. return getR(c);
  668. case 1 :
  669. return getG(c);
  670. case 2 :
  671. return getB(c);
  672. default:
  673. return 0;
  674. }
  675. }
  676. // normalized versions
  677. final float getNR(color c) {
  678. return r255[(c & 0xff0000) >> 16];
  679. }
  680. final float getNG(color c) {
  681. return r255[(c & 0xff00) >> 8];
  682. }
  683. final float getNB(color c) {
  684. return r255[c & 0xff];
  685. }
  686. final float getNLuma(color c) {
  687. return r255[getLuma(c)];
  688. }
  689. color blendRGB(color c, int r, int g, int b) {
  690. return (c & 0xff000000) | (constrain(r, 0, 255) << 16) | (constrain(g, 0, 255) << 8 ) | constrain(b, 0, 255);
  691. }
  692. color blendRGB(color c, float r, float g, float b) {
  693. return blendRGB(c, (int)(r*255), (int)(g*255), (int)(b*255));
  694. }
  695. /**************
  696. * Greyscale
  697. **************/
  698. color tofromGS(color c) {
  699. int l = getLuma(c);
  700. return blendRGB(c, l, l, l);
  701. }
  702. /**************
  703. * YUV
  704. **************/
  705. final static float Umax = 0.436 * 255.0;
  706. final static float Vmax = 0.615 * 255.0;
  707. color toYUV(color c) {
  708. int R = getR(c);
  709. int G = getG(c);
  710. int B = getB(c);
  711. int Y = (int)( 0.299*R+0.587*G+0.114*B);
  712. int U = (int)map(-0.14713*R-0.28886*G+0.436*B,-Umax,Umax,0,255);
  713. int V = (int)map(0.615*R-0.51499*G-0.10001*B,-Vmax,Vmax,0,255);
  714. return blendRGB(c, Y, U, V);
  715. }
  716. color fromYUV(color c) {
  717. int Y = getR(c);
  718. float U = map(getG(c),0,255,-Umax,Umax);
  719. float V = map(getB(c),0,255,-Vmax,Vmax);
  720. int R = (int)(Y + 1.13983*V);
  721. int G = (int)(Y - 0.39465*U - 0.58060*V);
  722. int B = (int)(Y + 2.03211*U);
  723. return blendRGB(c, R, G, B);
  724. }
  725. /**************
  726. * YDbDr
  727. **************/
  728. color toYDbDr(color c) {
  729. int R = getR(c);
  730. int G = getG(c);
  731. int B = getB(c);
  732. int Y = (int)( 0.299*R+0.587*G+0.114*B);
  733. int Db = (int)(127.5+(-0.450*R-0.883*G+1.333*B)/2.666);
  734. int Dr = (int)(127.5+(-1.333*R+1.116*G+0.217*B)/2.666);
  735. return blendRGB(c, Y, Db, Dr);
  736. }
  737. color fromYDbDr(color c) {
  738. int Y = getR(c);
  739. float Db = (getG(c)-127.5)*2.666;
  740. float Dr = (getB(c)-127.5)*2.666;
  741. int R = (int)(Y + 9.2303716147657e-05*Db-0.52591263066186533*Dr);
  742. int G = (int)(Y - 0.12913289889050927*Db+0.26789932820759876*Dr);
  743. int B = (int)(Y + 0.66467905997895482*Db-7.9202543533108e-05*Dr);
  744. return blendRGB(c, R, G, B);
  745. }
  746. /**************
  747. * YCbCr
  748. **************/
  749. color toYCbCr(color c) {
  750. int R = getR(c);
  751. int G = getG(c);
  752. int B = getB(c);
  753. int Y = (int)( 0.2988390*R+0.5868110*G+0.1143500*B);
  754. int Cb = (int)(-0.168736*R-0.3312640*G+0.5000000*B+127.5);
  755. int Cr = (int)( 0.5000000*R-0.4186880*G-0.0813120*B+127.5);
  756. return blendRGB(c, Y, Cb, Cr);
  757. }
  758. color fromYCbCr(color c) {
  759. int Y = getR(c);
  760. float Cb = getG(c) - 127.5;
  761. float Cr = getB(c) - 127.5;
  762. int R = (int)(Y + 1.402*Cr)+1; // some fix
  763. int G = (int)(Y-0.344136*Cb-0.714136*Cr);
  764. int B = (int)(Y+1.772000*Cb)+1; // some fix
  765. return blendRGB(c, R, G, B);
  766. }
  767. /**************
  768. * YPbPr
  769. **************/
  770. color toYPbPr(color c) {
  771. int R = getR(c);
  772. int B = getB(c);
  773. int Y = getLuma(c);
  774. int Pb = B - Y;
  775. int Pr = R - Y;
  776. if(Pb<0) Pb+=256;
  777. if(Pr<0) Pr+=256;
  778. return blendRGB(c, Y, Pb, Pr);
  779. }
  780. color fromYPbPr(color c) {
  781. int Y = getR(c);
  782. int B = getG(c) + Y;
  783. int R = getB(c) + Y;
  784. if(R>255) R-=256;
  785. if(B>255) B-=256;
  786. int G = (int)((Y-0.2126*R-0.0722*B)/0.7152);
  787. return blendRGB(c, R, G, B);
  788. }
  789. /**************
  790. * R-G,G,B-G
  791. **************/
  792. color toRGGBG(color c) {
  793. int G = getG(c);
  794. int R = getR(c)-G;
  795. int B = getB(c)-G;
  796. if(R<0) R+=256;
  797. if(B<0) B+=256;
  798. return blendRGB(c, R, G, B);
  799. }
  800. color fromRGGBG(color c) {
  801. int G = getG(c);
  802. int R = getR(c)+G;
  803. int B = getB(c)+G;
  804. if(R>255) R-=256;
  805. if(B>255) B-=256;
  806. return blendRGB(c, R, G, B);
  807. }
  808. /**************
  809. * HWB
  810. **************/
  811. color toHSB(color c) {
  812. int R = getR(c);
  813. int G = getG(c);
  814. int B = getB(c);
  815. int _min = min(R, G, B);
  816. int _max = max(R, G, B);
  817. float delta = _max-_min;
  818. float saturation = delta/_max;
  819. float brightness = r255[_max];
  820. if (delta == 0.0) return blendRGB(c, 0.0, saturation, brightness);
  821. float hue = 0;
  822. if (R == _max) hue = (G-B)/delta;
  823. else if (G == _max) hue = 2.0 + (B-R)/delta;
  824. else hue = 4.0 + (R-G)/delta;
  825. hue /= 6.0;
  826. if (hue < 0.0) hue += 1.0;
  827. return blendRGB(c, hue, saturation, brightness);
  828. }
  829. color fromHSB(color c) {
  830. float S = getNG(c);
  831. float B = getNB(c);
  832. if (S == 0.0) return blendRGB(c, B, B, B);
  833. float h = 6.0 * getNR(c);
  834. float f = h-floor(h);
  835. float p = B*(1.0-S);
  836. float q = B*(1.0-S*f);
  837. float t = B*(1.0-(S*(1.0-f)));
  838. float r, g, b;
  839. switch((int)h) {
  840. case 1:
  841. r=q;
  842. g=B;
  843. b=p;
  844. break;
  845. case 2:
  846. r=p;
  847. g=B;
  848. b=t;
  849. break;
  850. case 3:
  851. r=p;
  852. g=q;
  853. b=B;
  854. break;
  855. case 4:
  856. r=t;
  857. g=p;
  858. b=B;
  859. break;
  860. case 5:
  861. r=B;
  862. g=p;
  863. b=q;
  864. break;
  865. default:
  866. r=B;
  867. g=t;
  868. b=p;
  869. break;
  870. }
  871. return blendRGB(c, r, g, b);
  872. }
  873. /**************
  874. * HWB
  875. **************/
  876. color toHWB(color c) {
  877. int R = getR(c);
  878. int G = getG(c);
  879. int B = getB(c);
  880. int w = min(R, G, B);
  881. int v = max(R, G, B);
  882. int hue;
  883. if (v == w) hue = 255;
  884. else {
  885. float f = ((R == w) ? G-B : ((G == w) ? B-R : R-G));
  886. float p = (R == w) ? 3.0 : ((G == w) ? 5.0 : 1.0);
  887. hue = (int)map((p-f/(v-w))/6.0, 0, 1, 0, 254);
  888. }
  889. return blendRGB(c, hue, w, 255-v);
  890. }
  891. color fromHWB(color c) {
  892. int H = getR(c);
  893. int B = 255-getB(c);
  894. if (H == 255) return blendRGB(c, B, B, B);
  895. else {
  896. float hue = map(H, 0, 254, 0, 6);
  897. float v = r255[B];
  898. float whiteness = getNG(c);
  899. int i = (int)floor(hue);
  900. float f = hue-i;
  901. if ((i&0x01)!= 0) f=1.0-f;
  902. float n = whiteness+f*(v-whiteness);
  903. float r, g, b;
  904. switch(i) {
  905. case 1:
  906. r=n;
  907. g=v;
  908. b=whiteness;
  909. break;
  910. case 2:
  911. r=whiteness;
  912. g=v;
  913. b=n;
  914. break;
  915. case 3:
  916. r=whiteness;
  917. g=n;
  918. b=v;
  919. break;
  920. case 4:
  921. r=n;
  922. g=whiteness;
  923. b=v;
  924. break;
  925. case 5:
  926. r=v;
  927. g=whiteness;
  928. b=n;
  929. break;
  930. default:
  931. r=v;
  932. g=n;
  933. b=whiteness;
  934. break;
  935. }
  936. return blendRGB(c, r, g, b);
  937. }
  938. }
  939. /**************
  940. * Lab
  941. **************/
  942. final static float D65X=0.950456;
  943. final static float D65Y=1.0;
  944. final static float D65Z=1.088754;
  945. final static float CIEEpsilon=(216.0/24389.0);
  946. final static float CIEK=(24389.0/27.0);
  947. final static float CIEK2epsilon = CIEK * CIEEpsilon;
  948. final static float D65FX_4 = 4.0*D65X/(D65X+15.0*D65Y+3.0*D65Z);
  949. final static float D65FY_9 = 9.0*D65Y/(D65X+15.0*D65Y+3.0*D65Z);
  950. final static float RANGE_X = 100.0 * (0.4124+0.3576+0.1805);
  951. final static float RANGE_Y = 100.0;
  952. final static float RANGE_Z = 100.0 * (0.0193+0.1192+0.9505);
  953. final static float mepsilon = 1.0e-10;
  954. final static float corrratio = 1.0/2.4;
  955. final static float One_Third = 1.0/3.0;
  956. final static float one_hsixteen = 1.0/116.0;
  957. color toLAB(color c) {
  958. PVector xyz = _toXYZ(getNR(c), getNG(c), getNB(c));
  959. xyz.div(100.0);
  960. xyz.x /= D65X;
  961. xyz.y /= D65Y;
  962. xyz.z /= D65Z;
  963. float x, y, z;
  964. if (xyz.x > CIEEpsilon) {
  965. x = pow(xyz.x, One_Third);
  966. } else {
  967. x= (CIEK*xyz.x+16.0)*one_hsixteen;
  968. }
  969. if (xyz.y > CIEEpsilon) {
  970. y = pow(xyz.y, One_Third);
  971. } else {
  972. y = (CIEK*xyz.y+16.0)*one_hsixteen;
  973. }
  974. if (xyz.z > CIEEpsilon) {
  975. z = pow(xyz.z, One_Third);
  976. } else {
  977. z = (CIEK*xyz.z+16.0)*one_hsixteen;
  978. }
  979. float L = 255.0*(((116.0*y)-16.0)*0.01);
  980. float a = 255.0*(0.5*(x-y)+0.5);
  981. float b = 255.0*(0.5*(y-z)+0.5);
  982. return blendRGB(c, round(L), round(a), round(b));
  983. }
  984. color fromLAB(color c) {
  985. float L = 100*getNR(c);
  986. float a = getNG(c)-0.5;
  987. float b = getNB(c)-0.5;
  988. float y = (L+16.0)*one_hsixteen;
  989. float x = y+a;
  990. float z = y-b;
  991. float xxx=x*x*x;
  992. if (xxx>CIEEpsilon) {
  993. x = xxx;
  994. } else {
  995. x = (116.0*x-16.0)/CIEK;
  996. }
  997. float yyy=y*y*y;
  998. if (yyy>CIEEpsilon) {
  999. y = yyy;
  1000. } else {
  1001. y = L/CIEK;
  1002. }
  1003. float zzz=z*z*z;
  1004. if (zzz>CIEEpsilon) {
  1005. z = zzz;
  1006. } else {
  1007. z = (116.0*z-16.0)/CIEK;
  1008. }
  1009. return _fromXYZ(c, RANGE_X*x, RANGE_Y*y, RANGE_Z*z);
  1010. }
  1011. /**************
  1012. * Luv
  1013. **************/
  1014. final float PerceptibleReciprocal(float x) {
  1015. float sgn = x < 0.0 ? -1.0 : 1.0;
  1016. if ((sgn * x) >= mepsilon) return (1.0 / x);
  1017. return (sgn/mepsilon);
  1018. }
  1019. color toLUV(color c) {
  1020. PVector xyz = _toXYZ(getNR(c), getNG(c), getNB(c));
  1021. xyz.div(100.0);
  1022. float d = xyz.y; // / D65Y;
  1023. float L;
  1024. if (d > CIEEpsilon) L = 116.0*pow(d, One_Third)-16.0;
  1025. else L = CIEK * d;
  1026. float alpha = PerceptibleReciprocal(xyz.x + 15.0 * xyz.y + 3.0 * xyz.z);
  1027. float L13 = 13.0 * L;
  1028. float u = L13 * ((4.0 * alpha * xyz.x)-D65FX_4);
  1029. float v = L13 * ((9.0 * alpha * xyz.y)-D65FY_9);
  1030. L /= 100.0;
  1031. u=(u+134.0)/354.0;
  1032. v=(v+140.0)/262.0;
  1033. return blendRGB(c, round(L*255), round(u*255), round(v*255));
  1034. }
  1035. color fromLUV(color c) {
  1036. float L = 100.0*getNR(c);
  1037. float u = 354.0*getNG(c)-134.0;
  1038. float v = 262.0*getNB(c)-140.0;
  1039. float X, Y, Z;
  1040. if (L > CIEK2epsilon) Y = pow((L+16.0)*one_hsixteen, 3.0);
  1041. else Y = L/CIEK;
  1042. float L13 = 13.0*L;
  1043. float L52 = 52.0*L;
  1044. float Y5 = 5.0*Y;
  1045. float L13u = L52/(u+L13*D65FX_4);
  1046. X=((Y*((39.0*L/(v+L13*D65FY_9))-5.0))+Y5)/((((L13u)-1.0)/3.0)+One_Third);
  1047. Z=(X*(((L13u)-1.0)/3.0))-Y5;
  1048. return _fromXYZ(c, 100*X, 100*Y, 100*Z);
  1049. }
  1050. /**************
  1051. * HCL
  1052. **************/
  1053. color toHCL(color c) {
  1054. float r = getNR(c);
  1055. float g = getNG(c);
  1056. float b = getNB(c);
  1057. float max = max(r, max(g, b));
  1058. float chr = max - min(r, min(g, b));
  1059. float h = 0.0;
  1060. if ( chr != 0) {
  1061. if (r == max) {
  1062. h = ((g-b)/chr+6.0) % 6.0;
  1063. } else if (g == max) {
  1064. h = (b-r)/chr + 2.0;
  1065. } else {
  1066. h = (r-g)/chr + 4.0;
  1067. }
  1068. }
  1069. return blendRGB(c, round((h/6.0)*255), round(chr*255), round(255*(0.298839*r+0.586811*g+0.114350*b)));
  1070. }
  1071. color fromHCL(color c) {
  1072. float h = 6.0*getNR(c);
  1073. float chr = getNG(c);
  1074. float l = getNB(c);
  1075. float x = chr*(1.0-abs((h%2.0)-1.0));
  1076. float r = 0.0;
  1077. float g = 0.0;
  1078. float b = 0.0;
  1079. if ((0.0 <= h) && (h < 1.0)) {
  1080. r=chr;
  1081. g=x;
  1082. } else if ((1.0 <= h) && (h < 2.0)) {
  1083. r=x;
  1084. g=chr;
  1085. } else if ((2.0 <= h) && (h < 3.0)) {
  1086. g=chr;
  1087. b=x;
  1088. } else if ((3.0 <= h) && (h < 4.0)) {
  1089. g=x;
  1090. b=chr;
  1091. } else if ((4.0 <= h) && (h < 5.0)) {
  1092. r=x;
  1093. b=chr;
  1094. } else {//if ((5.0 <= h) && (h < 6.0)) {
  1095. r=chr;
  1096. b=x;
  1097. }
  1098. float m = l - (0.298839*r+0.586811*g+0.114350*b);
  1099. return blendRGB(c, round(255*(r+m)), round(255*(g+m)), round(255*(b+m)));
  1100. }
  1101. /**************
  1102. * Yxy
  1103. **************/
  1104. color toYXY(color c) {
  1105. PVector xyz = _toXYZ(getNR(c), getNG(c), getNB(c));
  1106. float sum = xyz.x + xyz.y + xyz.z;
  1107. float x = xyz.x > 0 ? xyz.x / sum : 0.0;
  1108. float y = xyz.y > 0 ? xyz.y / sum : 0.0;
  1109. return blendRGB(c,
  1110. (int)map(xyz.y, 0, RANGE_Y, 0, 255),
  1111. (int)map(x, 0.0, 1.0, 0, 255),
  1112. (int)map(y, 0.0, 1.0, 0, 255));
  1113. }
  1114. color fromYXY(color c) {
  1115. float Y = map(getR(c), 0, 255, 0, RANGE_Y);
  1116. float x = map(getG(c), 0, 255, 0, 1.0);
  1117. float y = map(getB(c), 0, 255, 0, 1.0);
  1118. float divy = Y / (y>0 ? y : 1.0e-6);
  1119. return _fromXYZ(c, x * divy, Y, (1-x-y)*divy);
  1120. }
  1121. /**************
  1122. * XYZ
  1123. **************/
  1124. // FIXME: range from 0 to 1
  1125. float correctionxyz(float n) {
  1126. return (n > 0.04045 ? pow((n + 0.055) / 1.055, 2.4) : n / 12.92) * 100.0;
  1127. }
  1128. PVector _toXYZ(float rr, float gg, float bb) {
  1129. float r = correctionxyz(rr);
  1130. float g = correctionxyz(gg);
  1131. float b = correctionxyz(bb);
  1132. return new PVector(r * 0.4124 + g * 0.3576 + b * 0.1805,
  1133. r * 0.2126 + g * 0.7152 + b * 0.0722,
  1134. r * 0.0193 + g * 0.1192 + b * 0.9505);
  1135. }
  1136. color toXYZ(color c) {
  1137. PVector xyz = _toXYZ(getNR(c), getNG(c), getNB(c));
  1138. return blendRGB(c,
  1139. (int)map(xyz.x, 0, RANGE_X, 0, 255),
  1140. (int)map(xyz.y, 0, RANGE_Y, 0, 255),
  1141. (int)map(xyz.z, 0, RANGE_Z, 0, 255));
  1142. }
  1143. float recorrectionxyz(float n) {
  1144. return n > 0.0031308 ? 1.055 * pow(n, corrratio) - 0.055 : 12.92 * n;
  1145. }
  1146. // FIXME: range from 0 to 1
  1147. color _fromXYZ(color c, float xx, float yy, float zz) {
  1148. float x = xx/100.0;
  1149. float y = yy/100.0;
  1150. float z = zz/100.0;
  1151. int r = round(255.0*recorrectionxyz(x * 3.2406 + y * -1.5372 + z * -0.4986));
  1152. int g = round(255.0*recorrectionxyz(x * -0.9689 + y * 1.8758 + z * 0.0415));
  1153. int b = round(255.0*recorrectionxyz(x * 0.0557 + y * -0.2040 + z * 1.0570));
  1154. return blendRGB(c, r, g, b);
  1155. }
  1156. color fromXYZ(color c) {
  1157. float x = map(getR(c), 0, 255, 0, RANGE_X);
  1158. float y = map(getG(c), 0, 255, 0, RANGE_Y);
  1159. float z = map(getB(c), 0, 255, 0, RANGE_Z);
  1160. return _fromXYZ(c, x, y, z);
  1161. }
  1162. /**************
  1163. * CMY
  1164. **************/
  1165. color toCMY(color c) {
  1166. return blendRGB(c, 255-getR(c), 255-getG(c), 255-getB(c));
  1167. }
  1168. color fromCMY(color c) {
  1169. return toCMY(c);
  1170. }
  1171. /**************
  1172. * OHTA
  1173. **************/
  1174. color fromOHTA(color c) {
  1175. int I1 = getR(c);
  1176. float I2 = map(getG(c), 0, 255, -127.5, 127.5);
  1177. float I3 = map(getB(c), 0, 255, -127.5, 127.5);
  1178. int R = (int)(I1+1.00000*I2-0.66668*I3);
  1179. int G = (int)(I1+1.33333*I3);
  1180. int B = (int)(I1-1.00000*I2-0.66668*I3);
  1181. return blendRGB(c, R, G, B);
  1182. }
  1183. color toOHTA(color c) {
  1184. int R = getR(c);
  1185. int G = getG(c);
  1186. int B = getB(c);
  1187. int I1 = (int)(0.33333*R+0.33334*G+0.33333*B);
  1188. int I2 = (int)map(0.5*(R-B), -127.5, 127.5, 0, 255);
  1189. int I3 = (int)map(-0.25000*R+0.50000*G-0.25000*B, -127.5, 127.5, 0, 255);
  1190. return blendRGB(c, I1, I2, I3);
  1191. }
  1192. ////
  1193. // 1/n table for n=0..255 - to speed up color conversions things
  1194. final static float[] r255 = {
  1195. 0.0, 0.003921569, 0.007843138, 0.011764706, 0.015686275, 0.019607844, 0.023529412, 0.02745098, 0.03137255, 0.03529412, 0.039215688,
  1196. 0.043137256, 0.047058824, 0.050980393, 0.05490196, 0.05882353, 0.0627451, 0.06666667, 0.07058824, 0.07450981, 0.078431375, 0.08235294,
  1197. 0.08627451, 0.09019608, 0.09411765, 0.09803922, 0.101960786, 0.105882354, 0.10980392, 0.11372549, 0.11764706, 0.12156863, 0.1254902,
  1198. 0.12941177, 0.13333334, 0.13725491, 0.14117648, 0.14509805, 0.14901961, 0.15294118, 0.15686275, 0.16078432, 0.16470589, 0.16862746,
  1199. 0.17254902, 0.1764706, 0.18039216, 0.18431373, 0.1882353, 0.19215687, 0.19607843, 0.2, 0.20392157, 0.20784314, 0.21176471, 0.21568628,
  1200. 0.21960784, 0.22352941, 0.22745098, 0.23137255, 0.23529412, 0.23921569, 0.24313726, 0.24705882, 0.2509804, 0.25490198, 0.25882354,
  1201. 0.2627451, 0.26666668, 0.27058825, 0.27450982, 0.2784314, 0.28235295, 0.28627452, 0.2901961, 0.29411766, 0.29803923, 0.3019608, 0.30588236,
  1202. 0.30980393, 0.3137255, 0.31764707, 0.32156864, 0.3254902, 0.32941177, 0.33333334, 0.3372549, 0.34117648, 0.34509805, 0.34901962, 0.3529412,
  1203. 0.35686275, 0.36078432, 0.3647059, 0.36862746, 0.37254903, 0.3764706, 0.38039216, 0.38431373, 0.3882353, 0.39215687, 0.39607844, 0.4,
  1204. 0.40392157, 0.40784314, 0.4117647, 0.41568628, 0.41960785, 0.42352942, 0.42745098, 0.43137255, 0.43529412, 0.4392157, 0.44313726,
  1205. 0.44705883, 0.4509804, 0.45490196, 0.45882353, 0.4627451, 0.46666667, 0.47058824, 0.4745098, 0.47843137, 0.48235294, 0.4862745, 0.49019608,
  1206. 0.49411765, 0.49803922, 0.5019608, 0.5058824, 0.50980395, 0.5137255, 0.5176471, 0.52156866, 0.5254902, 0.5294118, 0.53333336, 0.5372549,
  1207. 0.5411765, 0.54509807, 0.54901963, 0.5529412, 0.5568628, 0.56078434, 0.5647059, 0.5686275, 0.57254905, 0.5764706, 0.5803922, 0.58431375,
  1208. 0.5882353, 0.5921569, 0.59607846, 0.6, 0.6039216, 0.60784316, 0.6117647, 0.6156863, 0.61960787, 0.62352943, 0.627451, 0.6313726, 0.63529414,
  1209. 0.6392157, 0.6431373, 0.64705884, 0.6509804, 0.654902, 0.65882355, 0.6627451, 0.6666667, 0.67058825, 0.6745098, 0.6784314, 0.68235296,
  1210. 0.6862745, 0.6901961, 0.69411767, 0.69803923, 0.7019608, 0.7058824, 0.70980394, 0.7137255, 0.7176471, 0.72156864, 0.7254902, 0.7294118,
  1211. 0.73333335, 0.7372549, 0.7411765, 0.74509805, 0.7490196, 0.7529412, 0.75686276, 0.7607843, 0.7647059, 0.76862746, 0.77254903, 0.7764706,
  1212. 0.78039217, 0.78431374, 0.7882353, 0.7921569, 0.79607844, 0.8, 0.8039216, 0.80784315, 0.8117647, 0.8156863, 0.81960785, 0.8235294, 0.827451,
  1213. 0.83137256, 0.8352941, 0.8392157, 0.84313726, 0.84705883, 0.8509804, 0.85490197, 0.85882354, 0.8627451, 0.8666667, 0.87058824, 0.8745098,
  1214. 0.8784314, 0.88235295, 0.8862745, 0.8901961, 0.89411765, 0.8980392, 0.9019608, 0.90588236, 0.9098039, 0.9137255, 0.91764706, 0.92156863,
  1215. 0.9254902, 0.92941177, 0.93333334, 0.9372549, 0.9411765, 0.94509804, 0.9490196, 0.9529412, 0.95686275, 0.9607843, 0.9647059, 0.96862745,
  1216. 0.972549, 0.9764706, 0.98039216, 0.9843137, 0.9882353, 0.99215686, 0.99607843, 1.0
  1217. };