cgv
Loading...
Searching...
No Matches
color_map.h
1#pragma once
2
3#include <memory>
4
5#include <cgv/math/piecewise_linear_interpolator.h>
6#include <cgv/math/piecewise_nearest_interpolator.h>
7#include <cgv/render/context.h>
8#include <cgv/render/texture.h>
9
10namespace cgv {
11namespace render {
12
13class color_map {
14protected:
15 typedef rgb color_type;
16 typedef float opacity_type;
17 typedef std::pair<opacity_type, color_type> sample_point_type;
18 typedef cgv::math::control_point_container<color_type>::control_point_type color_control_point_type;
19 typedef cgv::math::control_point_container<opacity_type>::control_point_type opacity_control_point_type;
20
23
24 std::shared_ptr<cgv::math::interpolator<rgb>> color_interpolator_ptr = nullptr;
25 std::shared_ptr<cgv::math::interpolator<float>> opacity_interpolator_ptr = nullptr;
26
28 unsigned resolution = 256u;
30 bool use_interpolation = true;
31
32 void construct_interpolators() {
34 color_interpolator_ptr = std::make_shared<cgv::math::piecewise_linear_interpolator<rgb>>();
35 opacity_interpolator_ptr = std::make_shared<cgv::math::piecewise_linear_interpolator<float>>();
36 } else {
37 color_interpolator_ptr = std::make_shared<cgv::math::piecewise_nearest_interpolator<rgb>>();
38 opacity_interpolator_ptr = std::make_shared<cgv::math::piecewise_nearest_interpolator<float>>();
39 }
40 }
41
42public:
43 color_map() {
44 construct_interpolators();
45 }
46
47 color_map(const std::initializer_list<color_control_point_type> color_points) : color_map() {
48 this->color_points.assign(color_points);
49 }
50
51 color_map(const std::initializer_list<color_type> colors) : color_map() {
52 std::vector<color_control_point_type> color_points;
53 color_points.reserve(colors.size());
54
55 float step_size = 0.0f;
56 if(colors.size() > 0)
57 step_size = 1.0f / static_cast<float>(colors.size());
58
59 size_t i = 0;
60 for(const color_type& color : colors) {
61 color_points.push_back({ static_cast<float>(i) * step_size, color });
62 ++i;
63 }
64
65 this->color_points.assign(color_points);
66 }
67
68 color_map(const std::initializer_list<opacity_control_point_type> opacity_points) : color_map() {
69 this->opacity_points.assign(opacity_points);
70 }
71
72 color_map(const std::initializer_list<opacity_type> opacities) : color_map() {
73 std::vector<opacity_control_point_type> opacity_points;
74 opacity_points.reserve(opacities.size());
75
76 float step_size = 0.0f;
77 if(opacities.size() > 0)
78 step_size = 1.0f / static_cast<float>(opacities.size());
79
80 size_t i = 0;
81 for(const opacity_type& opacity : opacities) {
82 opacity_points.push_back({ static_cast<float>(i) * step_size, opacity });
83 ++i;
84 }
85
86 this->opacity_points.assign(opacity_points);
87 }
88
89 color_map(const std::initializer_list<std::pair<float, sample_point_type>> control_points) : color_map() {
90 std::vector<color_control_point_type> color_points;
91 std::vector<opacity_control_point_type> opacity_points;
92 color_points.reserve(control_points.size());
93 opacity_points.reserve(control_points.size());
94 for(const std::pair<float, sample_point_type>& control_point : control_points) {
95 color_points.push_back({ control_point.first, color_type(control_point.second.second) });
96 opacity_points.push_back({ control_point.first, control_point.second.first });
97 }
98
99 this->color_points.assign(color_points);
100 this->opacity_points.assign(opacity_points);
101 }
102
103 virtual ~color_map() {}
104
105 virtual bool has_texture_support() const {
106 return false;
107 }
108
109 void clear() {
110 color_points.clear();
111 opacity_points.clear();
112 }
113
114 void clear_color_points() {
115 color_points.clear();
116 }
117
118 void clear_opacity_points() {
119 opacity_points.clear();
120 }
121
122 bool empty() const {
123 return color_points.empty() && opacity_points.empty();
124 }
125
126 unsigned get_resolution() const { return resolution; }
127
128 void set_resolution(unsigned resolution) {
129 this->resolution = std::max(resolution, 2u);
130 }
131
132 bool is_interpolation_enabled() const { return use_interpolation; }
133
134 void enable_interpolation(bool enabled) {
135 use_interpolation = enabled;
136 construct_interpolators();
137 }
138
139 void flip() {
140 cgv::math::control_point_container<rgb> flipped_color_points;
141 cgv::math::control_point_container<float> flipped_opacity_points;
142
143 for(const color_control_point_type& color_point : color_points)
144 flipped_color_points.push_back(1.0f - color_point.first, color_point.second);
145
146 for(const opacity_control_point_type& opacity_point : opacity_points)
147 flipped_opacity_points.push_back(1.0f - opacity_point.first, opacity_point.second);
148
149 color_points = flipped_color_points;
150 opacity_points = flipped_opacity_points;
151 }
152
153 void apply_gamma(float gamma) {
154 cgv::math::control_point_container<rgb> corrected_color_points;
155
156 for(const color_control_point_type& color_point : color_points)
157 corrected_color_points.push_back(color_point.first, cgv::media::pow(color_point.second, gamma));
158
159 color_points = corrected_color_points;
160 }
161
162 void add_color_point(float t, rgb color) {
163 t = cgv::math::clamp(t, 0.0f, 1.0f);
164 color_points.push_back(t, color);
165 }
166
167 void add_opacity_point(float t, float opacity) {
168 t = cgv::math::clamp(t, 0.0f, 1.0f);
169 opacity_points.push_back(t, opacity);
170 }
171
172 const std::vector<color_control_point_type>& ref_color_points() const { return color_points.ref_points(); }
173 const std::vector<opacity_control_point_type>& ref_opacity_points() const { return opacity_points.ref_points(); }
174
175 rgb interpolate_color(float t) const {
176 return color_interpolator_ptr->interpolate(color_points, t);
177 }
178
179 std::vector<rgb> interpolate_color(size_t n) const {
180 return color_interpolator_ptr->interpolate(color_points, n);
181 }
182
183 float interpolate_opacity(float t) const {
184 return opacity_interpolator_ptr->interpolate(opacity_points, t);
185 }
186
187 std::vector<float> interpolate_opacity(size_t n) const {
188 return opacity_interpolator_ptr->interpolate(opacity_points, n);
189 }
190
191 rgba interpolate(float t) const {
192 rgb color = interpolate_color(t);
193 float opacity = interpolate_opacity(t);
194
195 return rgba(color.R(), color.G(), color.B(), opacity);
196 }
197
198 std::vector<rgba> interpolate(size_t n) const {
199 const std::vector<rgb>& colors = interpolate_color(n);
200 const std::vector<float>& opacities = interpolate_opacity(n);
201
202 std::vector<rgba> data(n);
203 for(size_t i = 0; i < n; ++i) {
204 const rgb& color = colors[i];
205 data[i] = rgba(color.R(), color.G(), color.B(), opacities[i]);
206 }
207
208 return data;
209 }
210};
211
212class gl_color_map : public color_map {
213protected:
216 texture tex;
217
218 TextureFilter get_texture_filter() {
219 return use_linear_filtering ? TF_LINEAR : TF_NEAREST;
220 }
221
222 void setup_texture(bool use_opacity) {
223 std::string format = use_opacity ? "uint8[R,G,B,A]" : "uint8[R,G,B]";
224 TextureFilter filter = get_texture_filter();
225 tex = texture(format, filter, filter);
226 }
227
228 void generate_rgb_texture(context& ctx) {
229 std::vector<rgb> data = interpolate_color(static_cast<size_t>(resolution));
230
231 std::vector<uint8_t> data_8(3 * data.size());
232 for(size_t i = 0; i < data.size(); ++i) {
233 rgb col = data[i];
234 data_8[3 * i + 0] = static_cast<uint8_t>(255.0f * col.R());
235 data_8[3 * i + 1] = static_cast<uint8_t>(255.0f * col.G());
236 data_8[3 * i + 2] = static_cast<uint8_t>(255.0f * col.B());
237 }
238
240
241 unsigned width = (unsigned)tex.get_width();
242
243 bool replaced = false;
244 if(tex.is_created() && width == resolution && tex.get_nr_components() == 3) {
245 TextureFilter filter = get_texture_filter();
246 tex.set_min_filter(filter);
247 tex.set_mag_filter(filter);
248 replaced = tex.replace(ctx, 0, dv);
249 }
250
251 if(!replaced) {
252 tex.destruct(ctx);
253 setup_texture(false);
254 tex.create(ctx, dv, 0);
255 }
256 }
257
258 void generate_rgba_texture(context& ctx) {
259 std::vector<rgba> data = interpolate(static_cast<size_t>(resolution));
260
261 std::vector<uint8_t> data_8(4 * data.size());
262 for(size_t i = 0; i < data.size(); ++i) {
263 rgba col = data[i];
264 data_8[4 * i + 0] = static_cast<uint8_t>(255.0f * col.R());
265 data_8[4 * i + 1] = static_cast<uint8_t>(255.0f * col.G());
266 data_8[4 * i + 2] = static_cast<uint8_t>(255.0f * col.B());
267 data_8[4 * i + 3] = static_cast<uint8_t>(255.0f * col.alpha());
268 }
269
271
272 unsigned width = (unsigned)tex.get_width();
273
274 bool replaced = false;
275 if(tex.is_created() && width == resolution && tex.get_nr_components() == 4) {
276 TextureFilter filter = get_texture_filter();
277 tex.set_min_filter(filter);
278 tex.set_mag_filter(filter);
279 replaced = tex.replace(ctx, 0, dv);
280 }
281
282 if(!replaced) {
283 tex.destruct(ctx);
284 setup_texture(true);
285 tex.create(ctx, dv, 0);
286 }
287 }
288
289public:
290 gl_color_map() : color_map() {}
291
292 gl_color_map(unsigned resolution) : gl_color_map() {
293 resolution = std::max(resolution, 2u);
294 }
295
296 gl_color_map(const color_map& cm) : gl_color_map() {
297 resolution = cm.get_resolution();
298 use_interpolation = cm.is_interpolation_enabled();
299
300 construct_interpolators();
301
302 for(auto& p : cm.ref_color_points())
303 add_color_point(p.first, p.second);
304 for(auto& p : cm.ref_opacity_points())
305 add_opacity_point(p.first, p.second);
306 }
307
308 virtual ~gl_color_map() {
309 clear();
310 }
311
312 virtual bool has_texture_support() const {
313 return true;
314 }
315
316 void clear() {
317 color_map::clear();
318 }
319
320 bool destruct(context& ctx) {
321 if(tex.is_created())
322 return tex.destruct(ctx);
323 return true;
324 }
325
326 bool is_linear_filtering_enabled() const { return use_linear_filtering; }
327
328 void enable_linear_filtering(bool enabled) {
329 use_linear_filtering = enabled;
330 construct_interpolators();
331 }
332
333 bool init(context& ctx) {
334 std::vector<uint8_t> data(3 * resolution);
335
336 tex.destruct(ctx);
338 setup_texture(false);
339 return tex.create(ctx, dv, 0);
340 }
341
342 void generate_texture(context& ctx) {
343
344 if(ref_opacity_points().size() > 0)
345 generate_rgba_texture(ctx);
346 else
347 generate_rgb_texture(ctx);
348 }
349
350 texture& ref_texture() { return tex; }
351};
352
353} // namespace render
354} // namespace cgv
unsigned int get_nr_components() const
return the number of components
A data_format describes a multidimensional data block of data entries.
Definition data_format.h:17
size_t get_width() const
return the resolution in the first dimension, or 1 if not defined
the data view gives access to a data array of one, two, three or four dimensions.
Definition data_view.h:153
unsigned resolution
resolution of the sampled color map; mostly used when generating textures from color maps
Definition color_map.h:28
bool use_interpolation
whether to use interpolation between the samples or just take the nearest one
Definition color_map.h:30
bool use_linear_filtering
whether to use linear or nearest neighbour texture filtering
Definition color_map.h:215
virtual bool is_created() const
return whether component has been created
Definition context.cxx:2046
the texture class encapsulates all functionality independent of the rendering api.
Definition texture.h:15
void set_mag_filter(TextureFilter _mag_filter)
set the magnification filter
Definition texture.cxx:138
bool create(const context &ctx, TextureType _tt=TT_UNDEF, unsigned width=-1, unsigned height=-1, unsigned depth=-1)
create the texture of dimension and resolution specified in the data format base class.
Definition texture.cxx:208
bool destruct(const context &ctx)
destruct the texture and free texture memory and handle
Definition texture.cxx:730
bool replace(const context &ctx, int x, const cgv::data::const_data_view &data, int level=-1, const std::vector< cgv::data::data_view > *palettes=0)
replace a block within a 1d texture with the given data.
Definition texture.cxx:621
void set_min_filter(TextureFilter _min_filter, float _anisotropy=2.0f)
set the minification filters, if minification is set to TF_ANISOTROP, the second floating point param...
Definition texture.cxx:120
@ CF_RGBA
color format with components R, G and B
@ CF_RGB
color format with two components R and G
TextureFilter
different texture filter
Definition context.h:189
@ TI_UINT8
signed integer stored in 64 bits
Definition type_id.h:23
the cgv namespace
Definition print.h:11
cgv::media::color< float, cgv::media::RGB, cgv::media::OPACITY > rgba
declare rgba color type with 32 bit components
Definition color.h:855
cgv::media::color< float, cgv::media::RGB > rgb
declare rgb color type with 32 bit components
Definition color.h:853