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@0: #include "opengl.h" nuclear@0: #include "rend_fast.h" nuclear@4: #include "sdr.h" nuclear@4: nuclear@10: #define DEF_PROXY_COUNT 512 nuclear@8: #define XFER_MAP_SZ 512 nuclear@4: nuclear@4: static unsigned int sdr; nuclear@4: static bool have_tex_float; nuclear@0: nuclear@0: RendererFast::RendererFast() nuclear@0: { nuclear@4: vol_tex = xfer_tex = 0; nuclear@4: vol_tex_valid = xfer_tex_valid = false; nuclear@10: proxy_count = DEF_PROXY_COUNT; nuclear@8: vbo_proxy_count = 0; nuclear@0: } nuclear@0: nuclear@0: bool RendererFast::init() nuclear@0: { nuclear@4: if(!sdr) { nuclear@4: if(!(sdr = create_program_load("sdr/fast.v.glsl", "sdr/fast.p.glsl"))) { nuclear@4: return false; nuclear@4: } nuclear@4: have_tex_float = GLEW_ARB_texture_float; nuclear@4: } nuclear@4: nuclear@0: glGenTextures(1, &vol_tex); nuclear@0: glBindTexture(GL_TEXTURE_3D, vol_tex); nuclear@0: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); nuclear@0: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@8: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); nuclear@8: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); nuclear@8: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); nuclear@0: nuclear@4: glGenTextures(1, &xfer_tex); nuclear@4: glBindTexture(GL_TEXTURE_1D, xfer_tex); nuclear@4: glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); nuclear@4: glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@8: glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); nuclear@6: glTexImage1D(GL_TEXTURE_1D, 0, have_tex_float ? GL_RGBA16F : GL_RGBA, XFER_MAP_SZ, 0, GL_RGB, GL_FLOAT, 0); nuclear@4: nuclear@8: glGenBuffers(1, &vbo); nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: void RendererFast::destroy() nuclear@0: { nuclear@0: glDeleteTextures(1, &vol_tex); nuclear@4: glDeleteTextures(1, &xfer_tex); nuclear@8: glDeleteBuffers(1, &vbo); nuclear@4: } nuclear@4: nuclear@4: void RendererFast::set_volume(Volume *vol) nuclear@4: { nuclear@4: vol_tex_valid = false; nuclear@4: Renderer::set_volume(vol); nuclear@4: } nuclear@4: nuclear@8: void RendererFast::set_proxy_count(int n) nuclear@8: { nuclear@8: proxy_count = n; nuclear@8: } nuclear@8: nuclear@8: int RendererFast::get_proxy_count() const nuclear@8: { nuclear@8: return proxy_count; nuclear@8: } nuclear@8: nuclear@0: void RendererFast::update(unsigned int msec) nuclear@0: { nuclear@0: if(!vol) return; nuclear@0: nuclear@0: // make sure the 3D volume texture is up to date nuclear@0: if(!vol_tex_valid) { nuclear@0: int xsz, ysz, zsz; nuclear@0: nuclear@0: if((xsz = vol->num_samples(0)) > 0) { nuclear@0: ysz = vol->num_samples(1); nuclear@0: zsz = vol->num_samples(2); nuclear@0: } else { nuclear@0: xsz = ysz = zsz = 256; nuclear@0: } nuclear@0: nuclear@4: printf("updating 3D texture data (%dx%dx%d) ... ", xsz, ysz, zsz); nuclear@4: fflush(stdout); nuclear@4: nuclear@0: int int_fmt = GLEW_ARB_texture_float ? GL_RGBA16F_ARB : GL_RGBA; nuclear@0: nuclear@0: glBindTexture(GL_TEXTURE_3D, vol_tex); nuclear@0: glTexImage3D(GL_TEXTURE_3D, 0, int_fmt, xsz, ysz, zsz, 0, GL_RGBA, GL_FLOAT, 0); nuclear@0: nuclear@0: float *slice = new float[xsz * ysz * 4]; nuclear@0: nuclear@0: for(int i=0; ivaluef(x, y, z); nuclear@0: // normal in rgb nuclear@0: vol->normalf(pptr, x, y, z); nuclear@0: // shift normal to the [0,1] range in case we don't have tex_float nuclear@0: pptr[0] = pptr[0] * 0.5 + 0.5; nuclear@0: pptr[1] = pptr[1] * 0.5 + 0.5; nuclear@0: pptr[2] = pptr[2] * 0.5 + 0.5; nuclear@4: nuclear@4: pptr += 4; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, i, xsz, ysz, 1, GL_RGBA, GL_FLOAT, slice); nuclear@0: } nuclear@0: nuclear@4: printf("done\n"); nuclear@4: nuclear@0: delete [] slice; nuclear@0: nuclear@0: vol_tex_valid = true; nuclear@0: } nuclear@4: nuclear@6: if(1) {//if(!xfer_tex_valid) { nuclear@6: float pixels[XFER_MAP_SZ * 4]; nuclear@4: float *pptr = pixels; nuclear@4: nuclear@4: for(int i=0; imap(x, pptr); nuclear@7: pptr[3] = std::max(pptr[0], std::max(pptr[1], pptr[2])); nuclear@6: } else { nuclear@6: pptr[0] = pptr[1] = pptr[2] = pptr[3] = x; nuclear@6: } nuclear@6: pptr += 4; nuclear@4: } nuclear@4: nuclear@4: glBindTexture(GL_TEXTURE_1D, xfer_tex); nuclear@6: glTexSubImage1D(GL_TEXTURE_1D, 0, 0, XFER_MAP_SZ, GL_RGBA, GL_FLOAT, pixels); nuclear@4: nuclear@4: xfer_tex_valid = true; nuclear@4: } nuclear@8: nuclear@8: // make sure the proxy object is up to date nuclear@8: if(proxy_count != vbo_proxy_count) { nuclear@8: static const float pat[][3] = {{-1, -1}, {1, -1}, {1, 1}, {-1, 1}}; nuclear@8: nuclear@8: int nverts = proxy_count * 4; nuclear@8: float *verts = new float[nverts * 3]; nuclear@8: float *vptr = verts; nuclear@8: nuclear@8: for(int i=0; i