lut-reader.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. 'use strict';
  2. (function() {
  3. function splitOnSpaceHandleQuotesWithEscapes(str, splits = ' \t\n\r') {
  4. const strs = [];
  5. let quoteType;
  6. let escape;
  7. let s = [];
  8. for (let i = 0; i < str.length; ++i) {
  9. const c = str[i];
  10. if (escape) {
  11. escape = false;
  12. s.push(c);
  13. } else {
  14. if (quoteType) { // we're inside quotes
  15. if (c === quoteType) {
  16. quoteType = undefined;
  17. strs.push(s.join(''));
  18. s = [];
  19. } else if (c === '\\') {
  20. escape = true;
  21. } else {
  22. s.push(c);
  23. }
  24. } else { // we're not in quotes
  25. if (splits.indexOf(c) >= 0) {
  26. if (s.length) {
  27. strs.push(s.join(''));
  28. s = [];
  29. }
  30. } else if (c === '"' || c === '\'') {
  31. if (s.length) { // its in th middle of a word
  32. s.push(c);
  33. } else {
  34. quoteType = c;
  35. }
  36. } else {
  37. s.push(c);
  38. }
  39. }
  40. }
  41. }
  42. if (s.length || strs.length === 0) {
  43. strs.push(s.join(''));
  44. }
  45. return strs;
  46. }
  47. function parse(str) {
  48. const data = [];
  49. const lut = {
  50. name: 'unknonw',
  51. type: '1D',
  52. size: 0,
  53. data,
  54. min: [0, 0, 0],
  55. max: [1, 1, 1],
  56. };
  57. const lines = str.split('\n');
  58. for (const origLine of lines) {
  59. const hashNdx = origLine.indexOf('#');
  60. const line = hashNdx >= 0 ? origLine.substring(0, hashNdx) : origLine;
  61. const parts = splitOnSpaceHandleQuotesWithEscapes(line);
  62. switch (parts[0].toUpperCase()) {
  63. case 'TITLE':
  64. lut.name = parts[1];
  65. break;
  66. case 'LUT_1D_SIZE':
  67. lut.size = parseInt(parts[1]);
  68. lut.type = '1D';
  69. break;
  70. case 'LUT_3D_SIZE':
  71. lut.size = parseInt(parts[1]);
  72. lut.type = '3D';
  73. break;
  74. case 'DOMAIN_MIN':
  75. lut.min = parts.slice(1).map(parseFloat);
  76. break;
  77. case 'DOMAIN_MAX':
  78. lut.max = parts.slice(1).map(parseFloat);
  79. break;
  80. default:
  81. if (parts.length === 3) {
  82. data.push(...parts.map(parseFloat));
  83. }
  84. break;
  85. }
  86. }
  87. if (!lut.min) {
  88. lut.min = data.slice(0, 3);
  89. lut.max = data.slice(data.length - 3, data.length);
  90. }
  91. if (!lut.size) {
  92. lut.size = data.length / 3;
  93. }
  94. return lut;
  95. }
  96. function lerp(a, b, t) {
  97. return a + (b - a) * t;
  98. }
  99. function lut1Dto3D(lut) {
  100. let src = lut.data;
  101. if (src.length / 3 !== lut.size) {
  102. src = [];
  103. for (let i = 0; i < lut.size; ++i) {
  104. const u = i / lut.size * lut.data.length;
  105. const i0 = (u | 0) * 3;
  106. const i1 = i0 + 3;
  107. const t = u % 1;
  108. src.push(
  109. lerp(lut.data[i0 + 0], lut.data[i1 + 0], t),
  110. lerp(lut.data[i0 + 0], lut.data[i1 + 1], t),
  111. lerp(lut.data[i0 + 0], lut.data[i1 + 2], t),
  112. );
  113. }
  114. }
  115. const data = [];
  116. for (let i = 0; i < lut.size * lut.size; ++i) {
  117. data.push(...src);
  118. }
  119. return Object.assign({}, lut, {data});
  120. }
  121. function lutTo2D3Drgb8(lut) {
  122. if (lut.type === '1D') {
  123. lut = lut1Dto3D(lut);
  124. }
  125. const min = lut.min;
  126. const max = lut.max;
  127. const range = min.map((min, ndx) => {
  128. return max[ndx] - min;
  129. });
  130. const src = lut.data;
  131. const data = new Uint8Array(src.length);
  132. for (let i = 0; i < src.length; i += 3) {
  133. data[i + 0] = (src[i + 0] - min[0]) / range[0] * 255;
  134. data[i + 1] = (src[i + 1] - min[1]) / range[1] * 255;
  135. data[i + 2] = (src[i + 2] - min[2]) / range[2] * 255;
  136. }
  137. return Object.assign({}, lut, {data});
  138. }
  139. window.lutParser = {
  140. parse,
  141. lutTo2D3Drgb8,
  142. };
  143. }());