nuclear@12: /* nuclear@12: glviewvol is an OpenGL 3D volume data viewer nuclear@12: Copyright (C) 2014 John Tsiombikas nuclear@12: nuclear@12: This program is free software: you can redistribute it and/or modify nuclear@12: it under the terms of the GNU General Public License as published by nuclear@12: the Free Software Foundation, either version 3 of the License, or nuclear@12: (at your option) any later version. nuclear@12: nuclear@12: This program is distributed in the hope that it will be useful, nuclear@12: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@12: GNU General Public License for more details. nuclear@12: nuclear@12: You should have received a copy of the GNU General Public License nuclear@12: along with this program. If not, see . nuclear@12: */ nuclear@7: #include nuclear@6: #include nuclear@6: #include "xfermap.h" nuclear@6: nuclear@6: TransferFunc::~TransferFunc() nuclear@6: { nuclear@6: } nuclear@6: nuclear@6: nuclear@6: // ---- TransferWindow ---- nuclear@6: nuclear@6: TransferWindow::TransferWindow() nuclear@6: { nuclear@6: soft_rad = 0.5; nuclear@7: for(int i=0; i<3; i++) { nuclear@6: low[i] = 0.5; nuclear@7: high[i] = 1.5; nuclear@6: } nuclear@6: } nuclear@6: nuclear@7: void TransferWindow::set_handle(int channel, int handle, float val) nuclear@7: { nuclear@7: float *dest = handle == HANDLE_LOW ? low : high; nuclear@7: nuclear@7: if(channel == -1) { nuclear@7: dest[0] = dest[1] = dest[2] = val; nuclear@7: } else { nuclear@7: dest[channel] = val; nuclear@7: } nuclear@7: } nuclear@7: nuclear@7: float TransferWindow::get_handle(int channel, int handle) const nuclear@7: { nuclear@7: const float *src = handle == HANDLE_LOW ? low : high; nuclear@7: nuclear@7: if(channel == -1) { nuclear@7: return src[0]; // XXX this doens't make much sense nuclear@7: } nuclear@7: return src[channel]; nuclear@7: } nuclear@7: nuclear@7: int TransferWindow::nearest_handle(int channel, float pos) const nuclear@7: { nuclear@7: float ldist = 0, hdist = 0; nuclear@7: nuclear@7: if(channel == -1) { nuclear@7: for(int i=0; i<3; i++) { nuclear@7: ldist += fabs(low[i] - pos); nuclear@7: hdist += fabs(high[i] - pos); nuclear@7: } nuclear@7: } else { nuclear@7: ldist = fabs(low[channel] - pos); nuclear@7: hdist = fabs(high[channel] - pos); nuclear@7: } nuclear@7: return ldist <= hdist ? HANDLE_LOW : HANDLE_HIGH; nuclear@7: } nuclear@7: nuclear@6: void TransferWindow::set_interval(float a, float b) nuclear@6: { nuclear@6: float v0 = std::min(a, b); nuclear@6: float v1 = std::max(a, b); nuclear@6: nuclear@7: for(int i=0; i<3; i++) { nuclear@6: low[i] = v0; nuclear@6: high[i] = v1; nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: void TransferWindow::set_interval(float *rgba_low, float *rgba_high) nuclear@6: { nuclear@7: for(int i=0; i<3; i++) { nuclear@6: low[i] = std::min(rgba_low[i], rgba_high[i]); nuclear@6: high[i] = std::max(rgba_low[i], rgba_high[i]); nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: void TransferWindow::set_interval_rgba(int channel, float a, float b) nuclear@6: { nuclear@6: low[channel] = std::min(a, b); nuclear@6: high[channel] = std::max(a, b); nuclear@6: } nuclear@6: nuclear@7: void TransferWindow::get_interval(float *aptr, float *bptr) const nuclear@7: { nuclear@7: *aptr = low[0]; nuclear@7: *bptr = high[0]; nuclear@7: } nuclear@7: nuclear@7: void TransferWindow::get_interval_rgba(float *rgba_low, float *rgba_high) const nuclear@7: { nuclear@7: for(int i=0; i<3; i++) { nuclear@7: rgba_low[i] = low[i]; nuclear@7: rgba_high[i] = high[i]; nuclear@7: } nuclear@7: } nuclear@7: nuclear@7: void TransferWindow::get_interval_rgba(int channel, float *aptr, float *bptr) const nuclear@7: { nuclear@7: *aptr = low[channel]; nuclear@7: *bptr = high[channel]; nuclear@7: } nuclear@7: nuclear@6: void TransferWindow::set_soft_radius(float s) nuclear@6: { nuclear@6: soft_rad = s; nuclear@6: } nuclear@6: nuclear@6: float TransferWindow::get_soft_radius() const nuclear@6: { nuclear@6: return soft_rad; nuclear@6: } nuclear@6: nuclear@6: static inline float smoothstep(float a, float b, float x) nuclear@6: { nuclear@6: if(x < a) return 0.0f; nuclear@6: if(x >= b) return 1.0f; nuclear@6: nuclear@6: float t = (x - a) / (b - a); nuclear@6: return t * t * (3.0f - 2.0f * t); nuclear@6: } nuclear@6: nuclear@6: float TransferWindow::map(float x) const nuclear@6: { nuclear@7: float rgb[3]; nuclear@7: map(x, rgb); nuclear@7: nuclear@7: return std::max(rgb[0], std::max(rgb[1], rgb[2])); nuclear@6: } nuclear@6: nuclear@7: void TransferWindow::map(float x, float *rgb_value) const nuclear@6: { nuclear@7: for(int i=0; i<3; i++) { nuclear@7: float val = smoothstep(low[i] - soft_rad, low[i] + soft_rad, x); nuclear@7: val *= 1.0 - smoothstep(high[i] - soft_rad, high[i] + soft_rad, x); nuclear@7: rgb_value[i] = val; nuclear@6: } nuclear@6: }