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@4: #include nuclear@7: #include nuclear@4: #include "opengl.h" nuclear@4: #include "xfer_view.h" nuclear@11: #include "viewer.h" nuclear@14: #include "volume.h" nuclear@14: nuclear@14: static void draw_histogram(); nuclear@4: nuclear@6: static TransferFunc *xfer; nuclear@14: static Volume *vol; nuclear@4: nuclear@7: static int act_color = -1; nuclear@7: static int grabbed_handle = -1; nuclear@7: static int mousex, mousey; nuclear@4: nuclear@6: bool xfview_init(TransferFunc *xferarg) nuclear@4: { nuclear@6: xfer = xferarg; nuclear@4: return true; nuclear@4: } nuclear@4: nuclear@4: void xfview_destroy() nuclear@4: { nuclear@4: } nuclear@4: nuclear@14: void xfview_set_volume(Volume *volarg) nuclear@14: { nuclear@14: vol = volarg; nuclear@14: } nuclear@14: nuclear@4: void xfview_draw() nuclear@4: { nuclear@4: float line_color[][3] = { nuclear@4: { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 1, 1, 1 } nuclear@4: }; nuclear@4: nuclear@4: glMatrixMode(GL_PROJECTION); nuclear@4: glLoadIdentity(); nuclear@7: glOrtho(0, 1, 0, 1, -1, 1); nuclear@7: nuclear@4: glMatrixMode(GL_MODELVIEW); nuclear@4: glLoadIdentity(); nuclear@4: nuclear@4: int xsz, ysz; nuclear@4: get_window_size(&xsz, &ysz); nuclear@4: int nsamples = xsz / 4; nuclear@4: nuclear@4: // paint the background a faint version of the selected color nuclear@4: glBegin(GL_QUADS); nuclear@7: int cidx = act_color == -1 ? 3 : act_color; nuclear@7: glColor3f(line_color[cidx][0] * 0.1, line_color[cidx][1] * 0.1, line_color[cidx][2] * 0.1); nuclear@4: glVertex2f(-1, -1); nuclear@4: glVertex2f(1, -1); nuclear@4: glVertex2f(1, 1); nuclear@4: glVertex2f(-1, 1); nuclear@4: glEnd(); nuclear@4: nuclear@14: draw_histogram(); nuclear@14: nuclear@4: glEnable(GL_LINE_SMOOTH); nuclear@4: nuclear@4: glEnable(GL_BLEND); nuclear@4: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); nuclear@4: nuclear@7: // draw handles on the selected curve nuclear@7: TransferWindow *xfwin = dynamic_cast(xfer); nuclear@7: if(xfwin) { nuclear@7: float dx = 1.0 / (float)xsz; nuclear@7: float cursor = (float)mousex / (float)xsz; nuclear@7: float low[3], high[3]; nuclear@7: xfwin->get_interval_rgba(low, high); nuclear@7: nuclear@7: if(act_color == -1) { // all curves nuclear@7: int nearest = xfwin->nearest_handle(-1, cursor); nuclear@7: nuclear@7: if(grabbed_handle != -1) { nuclear@7: glBegin(GL_LINES); nuclear@7: glColor3f(0.8, 0.8, 0.8); nuclear@7: for(int i=0; i<3; i++) { nuclear@7: float x = xfwin->get_handle(i, nearest); nuclear@7: float rad = xfwin->get_soft_radius(); nuclear@7: glVertex2f(x - rad, 0.5); nuclear@7: glVertex2f(x + rad, 0.5); nuclear@7: glVertex2f(x - rad, 0.4); nuclear@7: glVertex2f(x - rad, 0.6); nuclear@7: glVertex2f(x + rad, 0.4); nuclear@7: glVertex2f(x + rad, 0.6); nuclear@7: } nuclear@7: glEnd(); nuclear@7: } nuclear@7: nuclear@7: // draw handles on all lines, highlighting the nearest side of all of them nuclear@7: glBegin(GL_QUADS); nuclear@7: glColor3f(1, 1, 1); nuclear@7: nuclear@7: for(int i=0; i<3; i++) { nuclear@7: float x = nearest == TransferWindow::HANDLE_LOW ? low[i] : high[i]; nuclear@7: glVertex2f(x - 2.0 * dx, -1); nuclear@7: glVertex2f(x + 2.0 * dx, -1); nuclear@7: glVertex2f(x + 2.0 * dx, 1); nuclear@7: glVertex2f(x - 2.0 * dx, 1); nuclear@7: } nuclear@7: for(int i=0; i<3; i++) { nuclear@7: glColor3fv(line_color[i]); nuclear@7: glVertex2f(low[i] - dx, -1); nuclear@7: glVertex2f(low[i] + dx, -1); nuclear@7: glVertex2f(low[i] + dx, 1); nuclear@7: glVertex2f(low[i] - dx, 1); nuclear@7: glVertex2f(high[i] - dx, -1); nuclear@7: glVertex2f(high[i] + dx, -1); nuclear@7: glVertex2f(high[i] + dx, 1); nuclear@7: glVertex2f(high[i] - dx, 1); nuclear@7: } nuclear@7: glEnd(); nuclear@7: nuclear@7: } else { nuclear@7: int nearest = xfwin->nearest_handle(act_color, cursor); nuclear@7: float x = nearest == TransferWindow::HANDLE_LOW ? low[act_color] : high[act_color]; nuclear@7: nuclear@7: if(grabbed_handle != -1) { nuclear@7: float x = xfwin->get_handle(act_color, nearest); nuclear@7: float rad = xfwin->get_soft_radius(); nuclear@7: nuclear@7: glBegin(GL_LINES); nuclear@7: glColor3f(0.8, 0.8, 0.8); nuclear@7: glVertex2f(x - rad, 0.5); nuclear@7: glVertex2f(x + rad, 0.5); nuclear@7: glVertex2f(x - rad, 0.4); nuclear@7: glVertex2f(x - rad, 0.6); nuclear@7: glVertex2f(x + rad, 0.4); nuclear@7: glVertex2f(x + rad, 0.6); nuclear@7: glEnd(); nuclear@7: } nuclear@7: nuclear@7: nuclear@7: glBegin(GL_QUADS); nuclear@7: glColor3f(1, 1, 1); nuclear@7: glVertex2f(x - 2.0 * dx, -1); nuclear@7: glVertex2f(x + 2.0 * dx, -1); nuclear@7: glVertex2f(x + 2.0 * dx, 1); nuclear@7: glVertex2f(x - 2.0 * dx, 1); nuclear@7: nuclear@7: glColor3fv(line_color[act_color]); nuclear@7: for(int i=0; i<2; i++) { nuclear@7: glVertex2f(x - dx, -1); nuclear@7: glVertex2f(x + dx, -1); nuclear@7: glVertex2f(x + dx, 1); nuclear@7: glVertex2f(x - dx, 1); nuclear@7: x = nearest == TransferWindow::HANDLE_LOW ? high[act_color] : low[act_color]; nuclear@7: } nuclear@7: glEnd(); nuclear@7: } nuclear@7: } nuclear@7: nuclear@6: // draw curve nuclear@4: glLineWidth(2.0); nuclear@4: nuclear@7: for(int i=0; i<4; i++) { nuclear@4: int idx; nuclear@7: if(act_color == -1) { nuclear@7: idx = i; nuclear@4: } else { nuclear@7: idx = (i + act_color + 1) % 4; nuclear@4: } nuclear@4: nuclear@4: glColor3fv(line_color[idx]); nuclear@4: nuclear@4: glBegin(GL_LINE_STRIP); nuclear@4: for(int j=0; jmap(t, vval); nuclear@7: } else { nuclear@7: vval[3] = xfer->map(t); nuclear@7: } nuclear@7: nuclear@7: glVertex2f(t, vval[idx]); nuclear@4: } nuclear@4: glEnd(); nuclear@4: } nuclear@4: nuclear@4: glDisable(GL_BLEND); nuclear@4: } nuclear@4: nuclear@14: #define HIST_SAMPLES 256 nuclear@14: nuclear@14: static void draw_histogram() nuclear@14: { nuclear@14: VoxelVolume *voxvol = dynamic_cast(vol); nuclear@14: if(!voxvol) return; nuclear@14: nuclear@14: float *hist = voxvol->calc_histogram(HIST_SAMPLES); nuclear@14: if(!hist) return; nuclear@14: nuclear@14: float max_y = 0.0f; nuclear@14: for(int i=0; i max_y) { nuclear@14: max_y = hist[i]; nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: float dx = 1.0 / (float)HIST_SAMPLES; nuclear@14: glBegin(GL_QUADS); nuclear@14: glColor3f(0.6, 0.6, 0.6); nuclear@14: for(int i=0; i(xfer); nuclear@7: if(xfwin && press) { nuclear@7: float cursor = (float)x / (float)xsz; nuclear@7: float low[3], high[3]; nuclear@7: xfwin->get_interval_rgba(low, high); nuclear@7: nuclear@7: // grab the nearest handle nuclear@7: grabbed_handle = xfwin->nearest_handle(act_color, cursor); nuclear@5: } else { nuclear@7: grabbed_handle = -1; nuclear@5: } nuclear@7: redisplay(); nuclear@4: } nuclear@4: } nuclear@4: nuclear@4: void xfview_motion(int x, int y) nuclear@4: { nuclear@7: mousex = x; nuclear@7: mousey = y; nuclear@7: nuclear@7: int dx = x - prev_x; nuclear@7: int dy = y - prev_y; nuclear@7: prev_x = x; nuclear@7: prev_y = y; nuclear@7: nuclear@7: if(grabbed_handle != -1) { nuclear@7: TransferWindow *xfwin = dynamic_cast(xfer); nuclear@7: if(!xfwin) return; nuclear@7: nuclear@7: int xsz, ysz; nuclear@7: get_window_size(&xsz, &ysz); nuclear@7: nuclear@7: if(get_modifiers()) { nuclear@7: float soft = xfwin->get_soft_radius() + dy * 0.01; nuclear@7: if(soft < 0.0) soft = 0.0; nuclear@7: xfwin->set_soft_radius(soft); nuclear@7: } else { nuclear@7: float pos = (float)x / (float)xsz; nuclear@7: xfwin->set_handle(act_color, grabbed_handle, pos); nuclear@7: } nuclear@7: } nuclear@7: nuclear@7: redisplay(); nuclear@4: }