SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SLTexColorLUT.cpp
Go to the documentation of this file.
1 /**
2  * \file SLTexColorLUT.cpp
3  * \brief Implements a transfer function functionality
4  * \date July 2017
5  * \authors Marcus Hudritsch
6  * \copyright http://opensource.org/licenses/GPL-3.0
7  * \remarks Please use clangformat to format the code. See more code style on
8  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
9 */
10 
11 #include <SLTexColorLUT.h>
12 #include <SLAssetManager.h>
13 
14 //-----------------------------------------------------------------------------
15 //! Default ctor color LUT of a specific SLColorLUTType
17  SLColorLUTType lutType,
18  SLuint length)
19 {
20  _min_filter = GL_LINEAR;
21  _mag_filter = GL_LINEAR;
22  _wrap_s = GL_CLAMP_TO_EDGE;
23  _wrap_t = GL_CLAMP_TO_EDGE;
25  _length = length;
26  _target = GL_TEXTURE_2D; // OpenGL ES doesn't define 1D textures. We just make a 1 pixel high 2D texture
27 
28  colors(lutType);
29 
31 
32  // Add pointer to the global resource vectors for deallocation
33  if (assetMgr)
34  assetMgr->textures().push_back(this);
35 }
36 //-----------------------------------------------------------------------------
37 //! ctor with vector of alpha values and a predefined color LUT scheme
39  SLVAlphaLUTPoint alphaValues,
40  SLColorLUTType lutType,
41  SLuint length)
42 {
43  _min_filter = GL_LINEAR;
44  _mag_filter = GL_LINEAR;
45  _wrap_s = GL_CLAMP_TO_EDGE;
46  _wrap_t = GL_CLAMP_TO_EDGE;
48  _length = length;
49  _target = GL_TEXTURE_2D; // OpenGL ES doesn't define 1D textures. We just make a 1 pixel high 2D texture
50 
51  colors(lutType);
52 
53  for (auto alpha : alphaValues)
54  _alphas.push_back(alpha);
55 
57 
58  // Add pointer to the global resource vectors for deallocation
59  if (assetMgr)
60  assetMgr->textures().push_back(this);
61 }
62 //-----------------------------------------------------------------------------
63 //! ctor with vector of alpha and color values
65  SLVAlphaLUTPoint alphaValues,
66  SLVColorLUTPoint colorValues,
67  SLuint length)
68 {
69  _min_filter = GL_LINEAR;
70  _mag_filter = GL_LINEAR;
71  _wrap_s = GL_CLAMP_TO_EDGE;
72  _wrap_t = GL_CLAMP_TO_EDGE;
74  _length = length;
75  _target = GL_TEXTURE_2D; // OpenGL ES doesn't define 1D textures. We just make a 1 pixel high 2D texture
76 
77  for (auto color : colorValues)
78  _colors.push_back(color);
79 
80  for (auto alpha : alphaValues)
81  _alphas.push_back(alpha);
82 
84 
85  // Add pointer to the global resource vectors for deallocation
86  if (assetMgr)
87  assetMgr->textures().push_back(this);
88 }
89 //-----------------------------------------------------------------------------
91 {
92  _colors.clear();
93  _alphas.clear();
94 }
95 //-----------------------------------------------------------------------------
96 //! Colors setter function by predefined color LUT
98 {
99  assert(lutType != CLUT_custom && "SLTexColorLUT::colors: Custom LUT now allowed");
100 
101  _colors.clear();
102  _colorLUT = lutType;
103 
104  switch (lutType)
105  {
106  case CLUT_BW:
107  _colors.push_back(SLColorLUTPoint(SLCol3f::BLACK, 0.0f));
108  _colors.push_back(SLColorLUTPoint(SLCol3f::WHITE, 1.0f));
109  name("Gradient Texture (LUT): B-W");
110  break;
111  case CLUT_WB:
112  _colors.push_back(SLColorLUTPoint(SLCol3f::WHITE, 0.0f));
113  _colors.push_back(SLColorLUTPoint(SLCol3f::BLACK, 1.0f));
114  name("Gradient Texture (LUT): W-B");
115  break;
116  case CLUT_WYR:
117  _colors.push_back(SLColorLUTPoint(SLCol3f::WHITE, 0.0f));
118  _colors.push_back(SLColorLUTPoint(SLCol3f::YELLOW, 0.5f));
119  _colors.push_back(SLColorLUTPoint(SLCol3f::RED, 1.0f));
120  name("Gradient Texture (LUT): W-Y-R");
121  break;
122  case CLUT_RYGCB:
123  _colors.push_back(SLColorLUTPoint(SLCol3f::RED, 0.00f));
124  _colors.push_back(SLColorLUTPoint(SLCol3f::YELLOW, 0.25f));
125  _colors.push_back(SLColorLUTPoint(SLCol3f::GREEN, 0.50f));
126  _colors.push_back(SLColorLUTPoint(SLCol3f::CYAN, 0.75f));
127  _colors.push_back(SLColorLUTPoint(SLCol3f::BLUE, 1.00f));
128  name("Gradient Texture (LUT): R-Y-G-C-B");
129  break;
130  case CLUT_BCGYR:
131  _colors.push_back(SLColorLUTPoint(SLCol3f::BLUE, 0.00f));
132  _colors.push_back(SLColorLUTPoint(SLCol3f::CYAN, 0.25f));
133  _colors.push_back(SLColorLUTPoint(SLCol3f::GREEN, 0.50f));
134  _colors.push_back(SLColorLUTPoint(SLCol3f::YELLOW, 0.75f));
135  _colors.push_back(SLColorLUTPoint(SLCol3f::RED, 1.00f));
136  name("Gradient Texture (LUT): B-C-G-Y-R");
137  break;
138  case CLUT_RYGCBK:
139  _colors.push_back(SLColorLUTPoint(SLCol3f::RED, 0.00f));
140  _colors.push_back(SLColorLUTPoint(SLCol3f::YELLOW, 0.20f));
141  _colors.push_back(SLColorLUTPoint(SLCol3f::GREEN, 0.40f));
142  _colors.push_back(SLColorLUTPoint(SLCol3f::CYAN, 0.60f));
143  _colors.push_back(SLColorLUTPoint(SLCol3f::BLUE, 0.80f));
144  _colors.push_back(SLColorLUTPoint(SLCol3f::BLACK, 1.00f));
145  name("Gradient Texture (LUT): R-Y-G-C-B-K");
146  break;
147  case CLUT_KBCGYR:
148  _colors.push_back(SLColorLUTPoint(SLCol3f::BLACK, 0.00f));
149  _colors.push_back(SLColorLUTPoint(SLCol3f::BLUE, 0.20f));
150  _colors.push_back(SLColorLUTPoint(SLCol3f::CYAN, 0.40f));
151  _colors.push_back(SLColorLUTPoint(SLCol3f::GREEN, 0.60f));
152  _colors.push_back(SLColorLUTPoint(SLCol3f::YELLOW, 0.00f));
153  _colors.push_back(SLColorLUTPoint(SLCol3f::RED, 1.00f));
154  name("Gradient Texture (LUT): K-B-C-G-Y-R");
155  break;
156  case CLUT_RYGCBM:
157  _colors.push_back(SLColorLUTPoint(SLCol3f::RED, 0.00f));
158  _colors.push_back(SLColorLUTPoint(SLCol3f::YELLOW, 0.20f));
159  _colors.push_back(SLColorLUTPoint(SLCol3f::GREEN, 0.40f));
160  _colors.push_back(SLColorLUTPoint(SLCol3f::CYAN, 0.60f));
161  _colors.push_back(SLColorLUTPoint(SLCol3f::BLUE, 0.80f));
162  _colors.push_back(SLColorLUTPoint(SLCol3f::MAGENTA, 1.00f));
163  name("Gradient Texture (LUT): R-Y-G-C-B-M");
164  break;
165  case CLUT_MBCGYR:
166  _colors.push_back(SLColorLUTPoint(SLCol3f::MAGENTA, 0.00f));
167  _colors.push_back(SLColorLUTPoint(SLCol3f::BLUE, 0.20f));
168  _colors.push_back(SLColorLUTPoint(SLCol3f::CYAN, 0.40f));
169  _colors.push_back(SLColorLUTPoint(SLCol3f::GREEN, 0.60f));
170  _colors.push_back(SLColorLUTPoint(SLCol3f::YELLOW, 0.00f));
171  _colors.push_back(SLColorLUTPoint(SLCol3f::RED, 1.00f));
172  name("Gradient Texture (LUT): M-B-C-G-Y-R");
173  break;
174  case CLUT_DAYLIGHT:
175  // Daylight color ramp with white at noon in the middle
176  _colors.push_back(SLColorLUTPoint(SLCol3f(1, 36.0f / 255.0f, 36.0f / 255.0f), 0.00f));
177  _colors.push_back(SLColorLUTPoint(SLCol3f(1, 113.0f / 255.0f, 6.0f / 255.0f), 0.05f));
178  _colors.push_back(SLColorLUTPoint(SLCol3f(1, 243.0f / 255.0f, 6.0f / 255.0f), 0.10f));
179  _colors.push_back(SLColorLUTPoint(SLCol3f(1, 1, 245.0f / 255.0f), 0.20f));
180  _colors.push_back(SLColorLUTPoint(SLCol3f(1, 1, 1), 1.00f));
181  name("Gradient Texture (LUT): For daylight");
182  break;
183  default:
184  SL_EXIT_MSG("SLTexColorLUT::colors: undefined color LUT.");
185  break;
186  }
187 }
188 //-----------------------------------------------------------------------------
189 //! Generates the full 256 value LUT as 1x256 RGBA texture
191 {
192  assert(_length > 1);
193  assert(!_colors.empty() &&
194  "SLTexColorLUT::generateTexture: Not enough color values.");
195 
196  // Delete old data in case of regeneration
197  deleteData(false);
198 
199  SLfloat delta = 1.0f / (SLfloat)_length;
200 
201  // Check and sort alpha values
202  if (!_alphas.empty())
203  {
204  sort(_alphas.begin(),
205  _alphas.end(),
207  { return a.pos < b.pos; });
208 
209  // Check out of bounds position (0-1)
210  if (_alphas.front().pos < 0.0f)
211  SL_EXIT_MSG("SLTexColorLUT::generateTexture: Lower alpha pos below 0");
212  if (_alphas.back().pos > 1.0f)
213  SL_EXIT_MSG("SLTexColorLUT::generateTexture: Upper alpha pos above 1");
214  if (_colors.front().pos < 0.0f)
215  SL_EXIT_MSG("SLTexColorLUT::generateTexture: Lower color pos below 0");
216  if (_colors.back().pos > 1.0f)
217  SL_EXIT_MSG("SLTexColorLUT::generateTexture: Upper color pos above 1");
218 
219  // Add boundary node if they are not at position 0 or 1
220  if (_alphas.front().pos > 0.0f)
221  _alphas.insert(_alphas.begin(), SLAlphaLUTPoint(_alphas.front().alpha, 0.0f));
222  if (_alphas.back().pos < 1.0f)
223  _alphas.push_back(SLAlphaLUTPoint(_alphas.back().alpha, 1.0f));
224  if (_colors.front().pos > 0.0f)
225  _colors.insert(_colors.begin(), SLColorLUTPoint(_colors.front().color, 0.0f));
226  if (_colors.back().pos < 1.0f)
227  _colors.push_back(SLColorLUTPoint(_colors.back().color, 1.0f));
228 
229  // Check that the delta between positions is larger than delta
230  for (SLuint a = 0; a < _alphas.size() - 1; ++a)
231  if ((_alphas[a + 1].pos - _alphas[a].pos) < delta)
232  SL_EXIT_MSG("SLTexColorLUT::generateTexture: Alpha position deltas to small.");
233 
234  // Clamp alpha values
235  for (auto a : _alphas) a.alpha = Utils::clamp(a.alpha, 0.0f, 1.0f);
236  }
237 
238  // Check and sort color values
239  sort(_colors.begin(),
240  _colors.end(),
242  { return a.pos < b.pos; });
243 
244  // Check that the delta between positions is larger than delta
245  for (SLuint c = 0; c < _colors.size() - 1; ++c)
246  if ((_colors[c + 1].pos - _colors[c].pos) < delta)
247  SL_EXIT_MSG("SLTexColorLUT::generateTexture: Color position deltas to small.");
248 
249  // Clamp all colors
250  for (auto c : _colors)
251  c.color.clampMinMax(0.0f, 1.0f);
252 
253  // Finally create color LUT vector by lerping color and alpha values
254  SLuint c = 0; // current color segment index
255  SLfloat pos = 0.0f; // overall position between 0-1
256  SLfloat posC = 0.0f; // position in color segment
257  SLfloat deltaC = 1.0f / ((_colors[c + 1].pos - _colors[c].pos) / delta);
258 
259  SLVCol4f lut;
260  lut.resize((SLuint)_length);
261 
262  // Interpolate color values
263  for (SLuint i = 0; i < _length; ++i)
264  {
265  lut[i].r = Utils::lerp(posC, _colors[c].color.r, _colors[c + 1].color.r);
266  lut[i].g = Utils::lerp(posC, _colors[c].color.g, _colors[c + 1].color.g);
267  lut[i].b = Utils::lerp(posC, _colors[c].color.b, _colors[c + 1].color.b);
268 
269  pos += delta;
270  posC += deltaC;
271 
272  if (pos > _colors[c + 1].pos && c < _colors.size() - 2)
273  {
274  c++;
275  posC = 0.0f;
276  deltaC = 1.0f / ((_colors[c + 1].pos - _colors[c].pos) / delta);
277  }
278  }
279 
280  if (!_alphas.empty())
281  {
282  // Interpolate alpha value
283  SLuint a = 0; // current alpha segment index
284  SLfloat posA = 0.0f; // position in alpha segment
285  SLfloat deltaA = 1.0f / ((_alphas[a + 1].pos - _alphas[a].pos) / delta);
286  pos = 0.0f;
287  for (SLuint i = 0; i < _length; ++i)
288  {
289  lut[i].a = Utils::lerp(posA, _alphas[a].alpha, _alphas[a + 1].alpha);
290  pos += delta;
291  posA += deltaA;
292 
293  if (pos > _alphas[a + 1].pos && a < _alphas.size() - 2)
294  {
295  a++;
296  posA = 0.0f;
297  deltaA = 1.0f / ((_alphas[a + 1].pos - _alphas[a].pos) / delta);
298  }
299  }
300  }
301  else
302  {
303  for (SLuint i = 0; i < _length; ++i)
304  lut[i].a = 1.0f;
305  }
306 
307  // Create 1 x length sized image from SLCol4f values
308  load(lut);
309  _width = _images[0]->width();
310  _height = _images[0]->height();
311  _depth = (SLint)_images.size();
312 }
313 //-----------------------------------------------------------------------------
314 //! Returns all alpha values of the transfer function as a float vector
316 {
317  SLVfloat allA;
318  allA.resize(_length);
319 
320  for (SLuint i = 0; i < _length; ++i)
321  {
322  CVVec4f c4f = _images[0]->getPixeli((SLint)i, 0);
323  allA[i] = c4f[3];
324  }
325 
326  return allA;
327 }
328 //-----------------------------------------------------------------------------
329 //! Returns all alpha values of the transfer function as a float vector
331 {
332  // Finally create color LUT vector by lerping color and alpha values
333  SLuint c = 0; // current color segment index
334  SLfloat pos = 0.0f; // overall position between 0-1
335  SLfloat posC = 0.0f; // position in color segment
336  SLfloat delta = 1.0f / (SLfloat)_length;
337  SLfloat deltaC = 1.0f / ((_colors[c + 1].pos - _colors[c].pos) / delta);
338 
339  SLVCol3f lut;
340  lut.resize((SLuint)_length);
341 
342  // Interpolate color values
343  for (SLuint i = 0; i < _length; ++i)
344  {
345  lut[i].r = Utils::lerp(posC, _colors[c].color.r, _colors[c + 1].color.r);
346  lut[i].g = Utils::lerp(posC, _colors[c].color.g, _colors[c + 1].color.g);
347  lut[i].b = Utils::lerp(posC, _colors[c].color.b, _colors[c + 1].color.b);
348 
349  pos += delta;
350  posC += deltaC;
351 
352  if (pos > _colors[c + 1].pos && c < _colors.size() - 2)
353  {
354  c++;
355  posC = 0.0f;
356  deltaC = 1.0f / ((_colors[c + 1].pos - _colors[c].pos) / delta);
357  }
358  }
359  return lut;
360 }
361 //-----------------------------------------------------------------------------
cv::Vec4f CVVec4f
Definition: CVTypedefs.h:54
float SLfloat
Definition: SL.h:173
unsigned int SLuint
Definition: SL.h:171
vector< SLfloat > SLVfloat
Definition: SL.h:200
#define SL_EXIT_MSG(message)
Definition: SL.h:240
int SLint
Definition: SL.h:170
@ TT_diffuse
Definition: SLGLTexture.h:78
Declares a color look up table functionality.
vector< SLColorLUTPoint > SLVColorLUTPoint
Definition: SLTexColorLUT.h:47
SLColorLUTType
Predefined color lookup tables.
Definition: SLTexColorLUT.h:25
@ CLUT_WB
white to black
Definition: SLTexColorLUT.h:27
@ CLUT_RYGCBK
red to yellow to green to cyan to blue to black
Definition: SLTexColorLUT.h:31
@ CLUT_custom
enum for any other custom LUT
Definition: SLTexColorLUT.h:36
@ CLUT_MBCGYR
magenta to blue to cyan to green to yellow to red
Definition: SLTexColorLUT.h:34
@ CLUT_RYGCBM
red to yellow to green to cyan to blue to magenta
Definition: SLTexColorLUT.h:33
@ CLUT_DAYLIGHT
daylight from sunrise to sunset with noon in the middle
Definition: SLTexColorLUT.h:35
@ CLUT_BCGYR
blue to cyan to green to yellow to red
Definition: SLTexColorLUT.h:30
@ CLUT_RYGCB
red to yellow to green to cyan to blue
Definition: SLTexColorLUT.h:29
@ CLUT_KBCGYR
black to blue to cyan to green to yellow to red
Definition: SLTexColorLUT.h:32
@ CLUT_WYR
white to black
Definition: SLTexColorLUT.h:28
@ CLUT_BW
black to white
Definition: SLTexColorLUT.h:26
vector< SLAlphaLUTPoint > SLVAlphaLUTPoint
Definition: SLTexColorLUT.h:57
SLVec3< SLfloat > SLCol3f
Definition: SLVec3.h:319
vector< SLCol3f > SLVCol3f
Definition: SLVec3.h:326
vector< SLCol4f > SLVCol4f
Definition: SLVec4.h:241
Toplevel holder of the assets meshes, materials, textures and shaders.
SLVGLTexture & textures()
SLint _width
Texture image width in pixels (images exist either in _images or on the GPU or on both)
Definition: SLGLTexture.h:305
SLint _wrap_t
Wrapping in t direction.
Definition: SLGLTexture.h:314
SLint _min_filter
Minification filter.
Definition: SLGLTexture.h:311
void load(const SLstring &filename, SLbool flipVertical=true, SLbool loadGrayscaleIntoAlpha=false)
Loads the texture, converts color depth & applies vertical mirroring.
SLint _wrap_s
Wrapping in s direction.
Definition: SLGLTexture.h:313
SLint _height
Texture image height in pixels (images exist either in _images or on the GPU or on both)
Definition: SLGLTexture.h:306
SLTextureType _texType
See SLTextureType.
Definition: SLGLTexture.h:304
void deleteData(SLbool deleteAlsoOnGPU)
Delete all data (CVImages and GPU textures)
CVVImage _images
Vector of CVImage pointers.
Definition: SLGLTexture.h:302
SLint _depth
3D Texture image depth (images exist either in _images or on the GPU or on both)
Definition: SLGLTexture.h:307
SLenum _target
texture target
Definition: SLGLTexture.h:315
SLint _mag_filter
Magnification filter.
Definition: SLGLTexture.h:312
const SLstring & name() const
Definition: SLObject.h:38
SLVAlphaLUTPoint _alphas
vector of colors in TF
SLVColorLUTPoint _colors
Color LUT identifier.
SLTexColorLUT(SLAssetManager *assetMgr, SLColorLUTType lutType, SLuint length=256)
Default ctor color LUT of a specific SLColorLUTType.
SLVColorLUTPoint & colors()
Definition: SLTexColorLUT.h:94
SLColorLUTType _colorLUT
Length of transfer function (default 256)
SLVfloat allAlphas()
Returns all alpha values of the transfer function as a float vector.
SLVCol3f allColors()
Returns all alpha values of the transfer function as a float vector.
virtual ~SLTexColorLUT()
SLuint length()
Definition: SLTexColorLUT.h:93
void generateTexture()
Generates the full 256 value LUT as 1x256 RGBA texture.
static SLVec3 CYAN
Definition: SLVec3.h:292
static SLVec3 BLACK
Definition: SLVec3.h:286
static SLVec3 YELLOW
Definition: SLVec3.h:294
static SLVec3 GREEN
Definition: SLVec3.h:290
static SLVec3 BLUE
Definition: SLVec3.h:291
static SLVec3 MAGENTA
Definition: SLVec3.h:293
static SLVec3 WHITE
Definition: SLVec3.h:288
static SLVec3 RED
Definition: SLVec3.h:289
T clamp(T a, T min, T max)
Definition: Utils.h:253
T lerp(T x, T a, T b)
Definition: Utils.h:255
Alpha point with alpha value and position value between 0-1.
Definition: SLTexColorLUT.h:51
Color point with color and position value between 0-1.
Definition: SLTexColorLUT.h:41