rev |
line source |
nuclear@12
|
1 /*
|
nuclear@12
|
2 glviewvol is an OpenGL 3D volume data viewer
|
nuclear@12
|
3 Copyright (C) 2014 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@12
|
4
|
nuclear@12
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@12
|
6 it under the terms of the GNU General Public License as published by
|
nuclear@12
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@12
|
8 (at your option) any later version.
|
nuclear@12
|
9
|
nuclear@12
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@12
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@12
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@12
|
13 GNU General Public License for more details.
|
nuclear@12
|
14
|
nuclear@12
|
15 You should have received a copy of the GNU General Public License
|
nuclear@12
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@12
|
17 */
|
nuclear@7
|
18 #include <math.h>
|
nuclear@6
|
19 #include <algorithm>
|
nuclear@6
|
20 #include "xfermap.h"
|
nuclear@6
|
21
|
nuclear@6
|
22 TransferFunc::~TransferFunc()
|
nuclear@6
|
23 {
|
nuclear@6
|
24 }
|
nuclear@6
|
25
|
nuclear@6
|
26
|
nuclear@6
|
27 // ---- TransferWindow ----
|
nuclear@6
|
28
|
nuclear@6
|
29 TransferWindow::TransferWindow()
|
nuclear@6
|
30 {
|
nuclear@6
|
31 soft_rad = 0.5;
|
nuclear@7
|
32 for(int i=0; i<3; i++) {
|
nuclear@6
|
33 low[i] = 0.5;
|
nuclear@7
|
34 high[i] = 1.5;
|
nuclear@6
|
35 }
|
nuclear@6
|
36 }
|
nuclear@6
|
37
|
nuclear@7
|
38 void TransferWindow::set_handle(int channel, int handle, float val)
|
nuclear@7
|
39 {
|
nuclear@7
|
40 float *dest = handle == HANDLE_LOW ? low : high;
|
nuclear@7
|
41
|
nuclear@7
|
42 if(channel == -1) {
|
nuclear@7
|
43 dest[0] = dest[1] = dest[2] = val;
|
nuclear@7
|
44 } else {
|
nuclear@7
|
45 dest[channel] = val;
|
nuclear@7
|
46 }
|
nuclear@7
|
47 }
|
nuclear@7
|
48
|
nuclear@7
|
49 float TransferWindow::get_handle(int channel, int handle) const
|
nuclear@7
|
50 {
|
nuclear@7
|
51 const float *src = handle == HANDLE_LOW ? low : high;
|
nuclear@7
|
52
|
nuclear@7
|
53 if(channel == -1) {
|
nuclear@7
|
54 return src[0]; // XXX this doens't make much sense
|
nuclear@7
|
55 }
|
nuclear@7
|
56 return src[channel];
|
nuclear@7
|
57 }
|
nuclear@7
|
58
|
nuclear@7
|
59 int TransferWindow::nearest_handle(int channel, float pos) const
|
nuclear@7
|
60 {
|
nuclear@7
|
61 float ldist = 0, hdist = 0;
|
nuclear@7
|
62
|
nuclear@7
|
63 if(channel == -1) {
|
nuclear@7
|
64 for(int i=0; i<3; i++) {
|
nuclear@7
|
65 ldist += fabs(low[i] - pos);
|
nuclear@7
|
66 hdist += fabs(high[i] - pos);
|
nuclear@7
|
67 }
|
nuclear@7
|
68 } else {
|
nuclear@7
|
69 ldist = fabs(low[channel] - pos);
|
nuclear@7
|
70 hdist = fabs(high[channel] - pos);
|
nuclear@7
|
71 }
|
nuclear@7
|
72 return ldist <= hdist ? HANDLE_LOW : HANDLE_HIGH;
|
nuclear@7
|
73 }
|
nuclear@7
|
74
|
nuclear@6
|
75 void TransferWindow::set_interval(float a, float b)
|
nuclear@6
|
76 {
|
nuclear@6
|
77 float v0 = std::min(a, b);
|
nuclear@6
|
78 float v1 = std::max(a, b);
|
nuclear@6
|
79
|
nuclear@7
|
80 for(int i=0; i<3; i++) {
|
nuclear@6
|
81 low[i] = v0;
|
nuclear@6
|
82 high[i] = v1;
|
nuclear@6
|
83 }
|
nuclear@6
|
84 }
|
nuclear@6
|
85
|
nuclear@6
|
86 void TransferWindow::set_interval(float *rgba_low, float *rgba_high)
|
nuclear@6
|
87 {
|
nuclear@7
|
88 for(int i=0; i<3; i++) {
|
nuclear@6
|
89 low[i] = std::min(rgba_low[i], rgba_high[i]);
|
nuclear@6
|
90 high[i] = std::max(rgba_low[i], rgba_high[i]);
|
nuclear@6
|
91 }
|
nuclear@6
|
92 }
|
nuclear@6
|
93
|
nuclear@6
|
94 void TransferWindow::set_interval_rgba(int channel, float a, float b)
|
nuclear@6
|
95 {
|
nuclear@6
|
96 low[channel] = std::min(a, b);
|
nuclear@6
|
97 high[channel] = std::max(a, b);
|
nuclear@6
|
98 }
|
nuclear@6
|
99
|
nuclear@7
|
100 void TransferWindow::get_interval(float *aptr, float *bptr) const
|
nuclear@7
|
101 {
|
nuclear@7
|
102 *aptr = low[0];
|
nuclear@7
|
103 *bptr = high[0];
|
nuclear@7
|
104 }
|
nuclear@7
|
105
|
nuclear@7
|
106 void TransferWindow::get_interval_rgba(float *rgba_low, float *rgba_high) const
|
nuclear@7
|
107 {
|
nuclear@7
|
108 for(int i=0; i<3; i++) {
|
nuclear@7
|
109 rgba_low[i] = low[i];
|
nuclear@7
|
110 rgba_high[i] = high[i];
|
nuclear@7
|
111 }
|
nuclear@7
|
112 }
|
nuclear@7
|
113
|
nuclear@7
|
114 void TransferWindow::get_interval_rgba(int channel, float *aptr, float *bptr) const
|
nuclear@7
|
115 {
|
nuclear@7
|
116 *aptr = low[channel];
|
nuclear@7
|
117 *bptr = high[channel];
|
nuclear@7
|
118 }
|
nuclear@7
|
119
|
nuclear@6
|
120 void TransferWindow::set_soft_radius(float s)
|
nuclear@6
|
121 {
|
nuclear@6
|
122 soft_rad = s;
|
nuclear@6
|
123 }
|
nuclear@6
|
124
|
nuclear@6
|
125 float TransferWindow::get_soft_radius() const
|
nuclear@6
|
126 {
|
nuclear@6
|
127 return soft_rad;
|
nuclear@6
|
128 }
|
nuclear@6
|
129
|
nuclear@6
|
130 static inline float smoothstep(float a, float b, float x)
|
nuclear@6
|
131 {
|
nuclear@6
|
132 if(x < a) return 0.0f;
|
nuclear@6
|
133 if(x >= b) return 1.0f;
|
nuclear@6
|
134
|
nuclear@6
|
135 float t = (x - a) / (b - a);
|
nuclear@6
|
136 return t * t * (3.0f - 2.0f * t);
|
nuclear@6
|
137 }
|
nuclear@6
|
138
|
nuclear@6
|
139 float TransferWindow::map(float x) const
|
nuclear@6
|
140 {
|
nuclear@7
|
141 float rgb[3];
|
nuclear@7
|
142 map(x, rgb);
|
nuclear@7
|
143
|
nuclear@7
|
144 return std::max(rgb[0], std::max(rgb[1], rgb[2]));
|
nuclear@6
|
145 }
|
nuclear@6
|
146
|
nuclear@7
|
147 void TransferWindow::map(float x, float *rgb_value) const
|
nuclear@6
|
148 {
|
nuclear@7
|
149 for(int i=0; i<3; i++) {
|
nuclear@7
|
150 float val = smoothstep(low[i] - soft_rad, low[i] + soft_rad, x);
|
nuclear@7
|
151 val *= 1.0 - smoothstep(high[i] - soft_rad, high[i] + soft_rad, x);
|
nuclear@7
|
152 rgb_value[i] = val;
|
nuclear@6
|
153 }
|
nuclear@6
|
154 }
|