qvolray
changeset 11:8990b5d2c7fe
moving to qt
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 09 Apr 2012 23:42:57 +0300 |
parents | 9d2396738b60 |
children | 981fef9aa1be |
files | Makefile src/main.cc src/volray.c src/volray.cc src/volume.c src/volume.cc src/volume.h |
diffstat | 7 files changed, 991 insertions(+), 811 deletions(-) [+] |
line diff
1.1 --- a/Makefile Sun Apr 08 14:31:03 2012 +0300 1.2 +++ b/Makefile Mon Apr 09 23:42:57 2012 +0300 1.3 @@ -1,28 +1,228 @@ 1.4 -src = $(wildcard src/*.c) 1.5 -obj = $(src:.c=.o) 1.6 -dep = $(obj:.o=.d) 1.7 -bin = volray 1.8 +############################################################################# 1.9 +# Makefile for building: qvolray 1.10 +# Generated by qmake (2.01a) (Qt 4.7.4) on: Mon Apr 9 23:25:44 2012 1.11 +# Project: qvolray.pro 1.12 +# Template: app 1.13 +# Command: /usr/bin/qmake -o Makefile qvolray.pro 1.14 +############################################################################# 1.15 1.16 -CC = gcc 1.17 -CFLAGS = -pedantic -Wall -g $(incdir) 1.18 -LDFLAGS = $(libdir) $(libgl) -limago -lvmath -lm 1.19 +####### Compiler, tools and options 1.20 1.21 -ifeq ($(shell uname -s), Darwin) 1.22 - libgl = -framework OpenGL -framework GLUT -lGLEW 1.23 - incdir = -I/opt/local/include 1.24 - libdir = -L/opt/local/lib 1.25 -else 1.26 - libgl = -lGL -lglut -lGLEW 1.27 -endif 1.28 +CC = gcc 1.29 +CXX = g++ 1.30 +DEFINES = -DQT_WEBKIT -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED 1.31 +CFLAGS = -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES) 1.32 +CXXFLAGS = -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES) 1.33 +INCPATH = -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtOpenGL -I/usr/include/qt4 -I. -Isrc -I/usr/X11R6/include -I. 1.34 +LINK = g++ 1.35 +LFLAGS = -Wl,-O1 1.36 +LIBS = $(SUBLIBS) -L/usr/lib -L/usr/X11R6/lib -lQtOpenGL -lQtGui -lQtCore -lGLU -lGL -lpthread 1.37 +AR = ar cqs 1.38 +RANLIB = 1.39 +QMAKE = /usr/bin/qmake 1.40 +TAR = tar -cf 1.41 +COMPRESS = gzip -9f 1.42 +COPY = cp -f 1.43 +SED = sed 1.44 +COPY_FILE = $(COPY) 1.45 +COPY_DIR = $(COPY) -r 1.46 +STRIP = strip 1.47 +INSTALL_FILE = install -m 644 -p 1.48 +INSTALL_DIR = $(COPY_DIR) 1.49 +INSTALL_PROGRAM = install -m 755 -p 1.50 +DEL_FILE = rm -f 1.51 +SYMLINK = ln -f -s 1.52 +DEL_DIR = rmdir 1.53 +MOVE = mv -f 1.54 +CHK_DIR_EXISTS= test -d 1.55 +MKDIR = mkdir -p 1.56 1.57 -$(bin): $(obj) 1.58 - $(CC) -o $@ $(obj) $(LDFLAGS) 1.59 +####### Output directory 1.60 1.61 --include $(dep) 1.62 +OBJECTS_DIR = ./ 1.63 1.64 -%.d: %.c 1.65 - @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ 1.66 +####### Files 1.67 1.68 -.PHONY: clean 1.69 -clean: 1.70 - rm -f $(obj) $(bin) 1.71 +SOURCES = src/main.cc \ 1.72 + src/sdr.c \ 1.73 + src/volray.cc \ 1.74 + src/volume.cc 1.75 +OBJECTS = main.o \ 1.76 + sdr.o \ 1.77 + volray.o \ 1.78 + volume.o 1.79 +DIST = /usr/share/qt4/mkspecs/common/g++.conf \ 1.80 + /usr/share/qt4/mkspecs/common/unix.conf \ 1.81 + /usr/share/qt4/mkspecs/common/linux.conf \ 1.82 + /usr/share/qt4/mkspecs/qconfig.pri \ 1.83 + /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \ 1.84 + /usr/share/qt4/mkspecs/features/qt_functions.prf \ 1.85 + /usr/share/qt4/mkspecs/features/qt_config.prf \ 1.86 + /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ 1.87 + /usr/share/qt4/mkspecs/features/default_pre.prf \ 1.88 + /usr/share/qt4/mkspecs/features/release.prf \ 1.89 + /usr/share/qt4/mkspecs/features/default_post.prf \ 1.90 + /usr/share/qt4/mkspecs/features/warn_on.prf \ 1.91 + /usr/share/qt4/mkspecs/features/qt.prf \ 1.92 + /usr/share/qt4/mkspecs/features/unix/opengl.prf \ 1.93 + /usr/share/qt4/mkspecs/features/unix/thread.prf \ 1.94 + /usr/share/qt4/mkspecs/features/moc.prf \ 1.95 + /usr/share/qt4/mkspecs/features/resources.prf \ 1.96 + /usr/share/qt4/mkspecs/features/uic.prf \ 1.97 + /usr/share/qt4/mkspecs/features/yacc.prf \ 1.98 + /usr/share/qt4/mkspecs/features/lex.prf \ 1.99 + /usr/share/qt4/mkspecs/features/include_source_dir.prf \ 1.100 + qvolray.pro 1.101 +QMAKE_TARGET = qvolray 1.102 +DESTDIR = 1.103 +TARGET = qvolray 1.104 + 1.105 +first: all 1.106 +####### Implicit rules 1.107 + 1.108 +.SUFFIXES: .o .c .cpp .cc .cxx .C 1.109 + 1.110 +.cpp.o: 1.111 + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" 1.112 + 1.113 +.cc.o: 1.114 + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" 1.115 + 1.116 +.cxx.o: 1.117 + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" 1.118 + 1.119 +.C.o: 1.120 + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<" 1.121 + 1.122 +.c.o: 1.123 + $(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<" 1.124 + 1.125 +####### Build rules 1.126 + 1.127 +all: Makefile $(TARGET) 1.128 + 1.129 +$(TARGET): $(OBJECTS) 1.130 + $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS) 1.131 + 1.132 +Makefile: qvolray.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/g++.conf \ 1.133 + /usr/share/qt4/mkspecs/common/unix.conf \ 1.134 + /usr/share/qt4/mkspecs/common/linux.conf \ 1.135 + /usr/share/qt4/mkspecs/qconfig.pri \ 1.136 + /usr/share/qt4/mkspecs/modules/qt_webkit_version.pri \ 1.137 + /usr/share/qt4/mkspecs/features/qt_functions.prf \ 1.138 + /usr/share/qt4/mkspecs/features/qt_config.prf \ 1.139 + /usr/share/qt4/mkspecs/features/exclusive_builds.prf \ 1.140 + /usr/share/qt4/mkspecs/features/default_pre.prf \ 1.141 + /usr/share/qt4/mkspecs/features/release.prf \ 1.142 + /usr/share/qt4/mkspecs/features/default_post.prf \ 1.143 + /usr/share/qt4/mkspecs/features/warn_on.prf \ 1.144 + /usr/share/qt4/mkspecs/features/qt.prf \ 1.145 + /usr/share/qt4/mkspecs/features/unix/opengl.prf \ 1.146 + /usr/share/qt4/mkspecs/features/unix/thread.prf \ 1.147 + /usr/share/qt4/mkspecs/features/moc.prf \ 1.148 + /usr/share/qt4/mkspecs/features/resources.prf \ 1.149 + /usr/share/qt4/mkspecs/features/uic.prf \ 1.150 + /usr/share/qt4/mkspecs/features/yacc.prf \ 1.151 + /usr/share/qt4/mkspecs/features/lex.prf \ 1.152 + /usr/share/qt4/mkspecs/features/include_source_dir.prf \ 1.153 + /usr/lib/libQtOpenGL.prl \ 1.154 + /usr/lib/libQtGui.prl \ 1.155 + /usr/lib/libQtCore.prl 1.156 + $(QMAKE) -o Makefile qvolray.pro 1.157 +/usr/share/qt4/mkspecs/common/g++.conf: 1.158 +/usr/share/qt4/mkspecs/common/unix.conf: 1.159 +/usr/share/qt4/mkspecs/common/linux.conf: 1.160 +/usr/share/qt4/mkspecs/qconfig.pri: 1.161 +/usr/share/qt4/mkspecs/modules/qt_webkit_version.pri: 1.162 +/usr/share/qt4/mkspecs/features/qt_functions.prf: 1.163 +/usr/share/qt4/mkspecs/features/qt_config.prf: 1.164 +/usr/share/qt4/mkspecs/features/exclusive_builds.prf: 1.165 +/usr/share/qt4/mkspecs/features/default_pre.prf: 1.166 +/usr/share/qt4/mkspecs/features/release.prf: 1.167 +/usr/share/qt4/mkspecs/features/default_post.prf: 1.168 +/usr/share/qt4/mkspecs/features/warn_on.prf: 1.169 +/usr/share/qt4/mkspecs/features/qt.prf: 1.170 +/usr/share/qt4/mkspecs/features/unix/opengl.prf: 1.171 +/usr/share/qt4/mkspecs/features/unix/thread.prf: 1.172 +/usr/share/qt4/mkspecs/features/moc.prf: 1.173 +/usr/share/qt4/mkspecs/features/resources.prf: 1.174 +/usr/share/qt4/mkspecs/features/uic.prf: 1.175 +/usr/share/qt4/mkspecs/features/yacc.prf: 1.176 +/usr/share/qt4/mkspecs/features/lex.prf: 1.177 +/usr/share/qt4/mkspecs/features/include_source_dir.prf: 1.178 +/usr/lib/libQtOpenGL.prl: 1.179 +/usr/lib/libQtGui.prl: 1.180 +/usr/lib/libQtCore.prl: 1.181 +qmake: FORCE 1.182 + @$(QMAKE) -o Makefile qvolray.pro 1.183 + 1.184 +dist: 1.185 + @$(CHK_DIR_EXISTS) .tmp/qvolray1.0.0 || $(MKDIR) .tmp/qvolray1.0.0 1.186 + $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/qvolray1.0.0/ && $(COPY_FILE) --parents src/sdr.h src/volray.h src/volume.h .tmp/qvolray1.0.0/ && $(COPY_FILE) --parents src/main.cc src/sdr.c src/volray.cc src/volume.cc .tmp/qvolray1.0.0/ && (cd `dirname .tmp/qvolray1.0.0` && $(TAR) qvolray1.0.0.tar qvolray1.0.0 && $(COMPRESS) qvolray1.0.0.tar) && $(MOVE) `dirname .tmp/qvolray1.0.0`/qvolray1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/qvolray1.0.0 1.187 + 1.188 + 1.189 +clean:compiler_clean 1.190 + -$(DEL_FILE) $(OBJECTS) 1.191 + -$(DEL_FILE) *~ core *.core 1.192 + 1.193 + 1.194 +####### Sub-libraries 1.195 + 1.196 +distclean: clean 1.197 + -$(DEL_FILE) $(TARGET) 1.198 + -$(DEL_FILE) Makefile 1.199 + 1.200 + 1.201 +check: first 1.202 + 1.203 +mocclean: compiler_moc_header_clean compiler_moc_source_clean 1.204 + 1.205 +mocables: compiler_moc_header_make_all compiler_moc_source_make_all 1.206 + 1.207 +compiler_moc_header_make_all: 1.208 +compiler_moc_header_clean: 1.209 +compiler_rcc_make_all: 1.210 +compiler_rcc_clean: 1.211 +compiler_image_collection_make_all: qmake_image_collection.cpp 1.212 +compiler_image_collection_clean: 1.213 + -$(DEL_FILE) qmake_image_collection.cpp 1.214 +compiler_moc_source_make_all: main.moc 1.215 +compiler_moc_source_clean: 1.216 + -$(DEL_FILE) main.moc 1.217 +main.moc: src/volray.h \ 1.218 + src/main.cc 1.219 + /usr/bin/moc-qt4 $(DEFINES) $(INCPATH) src/main.cc -o main.moc 1.220 + 1.221 +compiler_uic_make_all: 1.222 +compiler_uic_clean: 1.223 +compiler_yacc_decl_make_all: 1.224 +compiler_yacc_decl_clean: 1.225 +compiler_yacc_impl_make_all: 1.226 +compiler_yacc_impl_clean: 1.227 +compiler_lex_make_all: 1.228 +compiler_lex_clean: 1.229 +compiler_clean: compiler_moc_source_clean 1.230 + 1.231 +####### Compile 1.232 + 1.233 +main.o: src/main.cc src/volray.h 1.234 + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o src/main.cc 1.235 + 1.236 +sdr.o: src/sdr.c src/sdr.h 1.237 + $(CC) -c $(CFLAGS) $(INCPATH) -o sdr.o src/sdr.c 1.238 + 1.239 +volray.o: src/volray.cc src/sdr.h \ 1.240 + src/volume.h 1.241 + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o volray.o src/volray.cc 1.242 + 1.243 +volume.o: src/volume.cc src/volume.h 1.244 + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o volume.o src/volume.cc 1.245 + 1.246 +####### Install 1.247 + 1.248 +install: FORCE 1.249 + 1.250 +uninstall: FORCE 1.251 + 1.252 +FORCE: 1.253 +
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/src/main.cc Mon Apr 09 23:42:57 2012 +0300 2.3 @@ -0,0 +1,51 @@ 2.4 +#include <QApplication> 2.5 +#include <QMainWindow> 2.6 +#include <QGLWidget> 2.7 +#include "volray.h" 2.8 + 2.9 +class GLView : public QGLWidget { 2.10 +private: 2.11 + Q_OBJECT; 2.12 + 2.13 + void initializeGL(); 2.14 + void resizeGL(int xsz, int ysz); 2.15 + void paintGL(); 2.16 + 2.17 +public: 2.18 + GLView(QWidget *parent = 0); 2.19 +}; 2.20 + 2.21 + 2.22 +int main(int argc, char **argv) 2.23 +{ 2.24 + QApplication app(argc, argv); 2.25 + 2.26 + QMainWindow win; 2.27 + GLView glview(&win); 2.28 + 2.29 + win.show(); 2.30 + app.exec(); 2.31 +} 2.32 + 2.33 + 2.34 +GLView::GLView(QWidget *parent) 2.35 + : QGLWidget(parent) 2.36 +{ 2.37 +} 2.38 + 2.39 +void GLView::initializeGL() 2.40 +{ 2.41 + glClearColor(1, 0, 0, 1); 2.42 + 2.43 + volray_init(); 2.44 +} 2.45 + 2.46 +void GLView::resizeGL(int xsz, int ysz) 2.47 +{ 2.48 + volray_resize(xsz, ysz); 2.49 +} 2.50 + 2.51 +void GLView::paintGL() 2.52 +{ 2.53 + volray_draw(); 2.54 +}
3.1 --- a/src/volray.c Sun Apr 08 14:31:03 2012 +0300 3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 3.3 @@ -1,531 +0,0 @@ 3.4 -#include <stdio.h> 3.5 -#include <stdlib.h> 3.6 -#include <assert.h> 3.7 - 3.8 -#include <GL/glew.h> 3.9 -#ifndef __APPLE__ 3.10 -#include <GL/glut.h> 3.11 -#else 3.12 -#include <GLUT/glut.h> 3.13 -#endif 3.14 - 3.15 -#include <vmath/vmath.h> 3.16 -#include <imago2.h> 3.17 -#include "sdr.h" 3.18 -#include "volume.h" 3.19 - 3.20 -#define XFER_MAP_SZ 512 3.21 - 3.22 -enum { 3.23 - UIMODE_DEFAULT, 3.24 - UIMODE_XFER, 3.25 - UIMODE_CURSOR 3.26 -}; 3.27 - 3.28 -int init(void); 3.29 -void disp(void); 3.30 -void render_volume(void); 3.31 -void draw_slice(void); 3.32 -void draw_xfer_func(void); 3.33 -void reshape(int x, int y); 3.34 -void keyb(unsigned char key, int x, int y); 3.35 -void keyb_up(unsigned char key, int x, int y); 3.36 -void mouse(int bn, int state, int x, int y); 3.37 -void motion(int x, int y); 3.38 -int parse_args(int argc, char **argv); 3.39 - 3.40 -static void create_ray_texture(int xsz, int ysz, float vfov, vec2_t *tex_scale); 3.41 -static vec3_t get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg); 3.42 -static int round_pow2(int x); 3.43 -static void create_transfer_map(float mean, float sdev); 3.44 - 3.45 -static float cam_theta = 0, cam_phi = 0, cam_dist = 4.0; 3.46 -static float cam_x, cam_y, cam_z; 3.47 - 3.48 -static vec2_t tex_scale; 3.49 -static struct volume *volume; 3.50 -static unsigned int vol_sdr, slice_sdr, ray_tex; 3.51 -static int win_xsz, win_ysz; 3.52 -static int raytex_needs_recalc = 1; 3.53 - 3.54 -static unsigned int xfer_tex; 3.55 -static float xfer_mean = 0.7, xfer_sdev = 0.1; 3.56 -static int xfertex_needs_recalc = 1; 3.57 - 3.58 -static int uimode; 3.59 -static float cur_z = 0.0; 3.60 -static float ray_step = 0.01; 3.61 - 3.62 -static const char *fname; 3.63 - 3.64 - 3.65 -int main(int argc, char **argv) 3.66 -{ 3.67 - glutInit(&argc, argv); 3.68 - glutInitWindowSize(1280, 720); 3.69 - glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 3.70 - 3.71 - if(parse_args(argc, argv) == -1) { 3.72 - return 1; 3.73 - } 3.74 - 3.75 - glutCreateWindow("Volume Raytracer"); 3.76 - 3.77 - glutDisplayFunc(disp); 3.78 - glutReshapeFunc(reshape); 3.79 - glutKeyboardFunc(keyb); 3.80 - glutKeyboardUpFunc(keyb_up); 3.81 - glutMouseFunc(mouse); 3.82 - glutMotionFunc(motion); 3.83 - 3.84 - glewInit(); 3.85 - 3.86 - if(init() == -1) { 3.87 - return 1; 3.88 - } 3.89 - 3.90 - glutMainLoop(); 3.91 - return 0; 3.92 -} 3.93 - 3.94 -int init(void) 3.95 -{ 3.96 - if(!(vol_sdr = create_program_load("sdr/volray.v.glsl", "sdr/volray.p.glsl"))) { 3.97 - return -1; 3.98 - } 3.99 - set_uniform_int(vol_sdr, "volume", 0); 3.100 - set_uniform_int(vol_sdr, "ray_tex", 1); 3.101 - set_uniform_int(vol_sdr, "xfer_tex", 2); 3.102 - set_uniform_float(vol_sdr, "ray_step", ray_step); 3.103 - set_uniform_float(vol_sdr, "zclip", cur_z); 3.104 - 3.105 - if(!(slice_sdr = create_program_load(0, "sdr/slice.p.glsl"))) { 3.106 - return -1; 3.107 - } 3.108 - set_uniform_int(slice_sdr, "volume", 0); 3.109 - set_uniform_int(slice_sdr, "xfer_tex", 1); 3.110 - 3.111 - if(!(volume = load_volume(fname))) { 3.112 - return -1; 3.113 - } 3.114 - 3.115 - return 0; 3.116 -} 3.117 - 3.118 -void disp(void) 3.119 -{ 3.120 - /* recalculate primary ray texture if needed */ 3.121 - if(raytex_needs_recalc) { 3.122 - create_ray_texture(win_xsz, win_ysz, 50.0, &tex_scale); 3.123 - } 3.124 - /* recalculate transfer function texture if needed */ 3.125 - if(xfertex_needs_recalc) { 3.126 - create_transfer_map(xfer_mean, xfer_sdev); 3.127 - } 3.128 - 3.129 - render_volume(); 3.130 - draw_slice(); 3.131 - draw_xfer_func(); 3.132 - 3.133 - glutSwapBuffers(); 3.134 - assert(glGetError() == GL_NO_ERROR); 3.135 -} 3.136 - 3.137 -void render_volume(void) 3.138 -{ 3.139 - /* set the camera transformation */ 3.140 - glMatrixMode(GL_MODELVIEW); 3.141 - glPushMatrix(); 3.142 - glLoadIdentity(); 3.143 - glRotatef(-90, 1, 0, 0); 3.144 - glTranslatef(cam_x, cam_y, -cam_z); 3.145 - glRotatef(cam_theta, 0, 1, 0); 3.146 - glRotatef(cam_phi, 1, 0, 0); 3.147 - glTranslatef(0, 0, -cam_dist); 3.148 - 3.149 - /* setup the texture matrix to map the useful part of the ray texture to [0,1] */ 3.150 - glMatrixMode(GL_TEXTURE); 3.151 - glPushMatrix(); 3.152 - glLoadIdentity(); 3.153 - glScalef(tex_scale.x, tex_scale.y, 1.0); 3.154 - 3.155 - /* tex unit0: volume data 3D texture */ 3.156 - glActiveTexture(GL_TEXTURE0); 3.157 - glBindTexture(GL_TEXTURE_3D, volume->tex_vol); 3.158 - glEnable(GL_TEXTURE_3D); 3.159 - 3.160 - /* tex unit1: primary rays in view space */ 3.161 - glActiveTexture(GL_TEXTURE1); 3.162 - glBindTexture(GL_TEXTURE_2D, ray_tex); 3.163 - glEnable(GL_TEXTURE_2D); 3.164 - 3.165 - /* tex unit2: transfer function (1d) */ 3.166 - glActiveTexture(GL_TEXTURE2); 3.167 - glBindTexture(GL_TEXTURE_1D, xfer_tex); 3.168 - glEnable(GL_TEXTURE_1D); 3.169 - 3.170 - bind_program(vol_sdr); 3.171 - glBegin(GL_QUADS); 3.172 - glColor3f(1, 1, 1); 3.173 - glTexCoord2f(0, 1); glVertex2f(-1, -1); 3.174 - glTexCoord2f(1, 1); glVertex2f(1, -1); 3.175 - glTexCoord2f(1, 0); glVertex2f(1, 1); 3.176 - glTexCoord2f(0, 0); glVertex2f(-1, 1); 3.177 - glEnd(); 3.178 - bind_program(0); 3.179 - 3.180 - glActiveTexture(GL_TEXTURE2); 3.181 - glDisable(GL_TEXTURE_1D); 3.182 - glActiveTexture(GL_TEXTURE1); 3.183 - glDisable(GL_TEXTURE_2D); 3.184 - glActiveTexture(GL_TEXTURE0); 3.185 - glDisable(GL_TEXTURE_3D); 3.186 - 3.187 - glMatrixMode(GL_TEXTURE); 3.188 - glPopMatrix(); 3.189 - glMatrixMode(GL_MODELVIEW); 3.190 - glPopMatrix(); 3.191 -} 3.192 - 3.193 -void draw_slice(void) 3.194 -{ 3.195 - glMatrixMode(GL_MODELVIEW); 3.196 - glPushMatrix(); 3.197 - glTranslatef(0.9, 0.9, 0); 3.198 - glScalef(0.3, 0.3 * ((float)win_xsz / win_ysz), 1); 3.199 - glTranslatef(-1, -1, 0); 3.200 - 3.201 - glActiveTexture(GL_TEXTURE0); 3.202 - glBindTexture(GL_TEXTURE_3D, volume->tex_vol); 3.203 - glEnable(GL_TEXTURE_3D); 3.204 - 3.205 - glActiveTexture(GL_TEXTURE1); 3.206 - glBindTexture(GL_TEXTURE_1D, xfer_tex); 3.207 - glEnable(GL_TEXTURE_1D); 3.208 - 3.209 - bind_program(slice_sdr); 3.210 - 3.211 - glBegin(GL_QUADS); 3.212 - glColor3f(1, 1, 1); 3.213 - glTexCoord3f(0, 1, cur_z); glVertex2f(-1, -1); 3.214 - glTexCoord3f(1, 1, cur_z); glVertex2f(1, -1); 3.215 - glTexCoord3f(1, 0, cur_z); glVertex2f(1, 1); 3.216 - glTexCoord3f(0, 0, cur_z); glVertex2f(-1, 1); 3.217 - glEnd(); 3.218 - 3.219 - bind_program(0); 3.220 - 3.221 - glActiveTexture(GL_TEXTURE1); 3.222 - glDisable(GL_TEXTURE_1D); 3.223 - glActiveTexture(GL_TEXTURE0); 3.224 - glDisable(GL_TEXTURE_3D); 3.225 - glPopMatrix(); 3.226 -} 3.227 - 3.228 -void draw_xfer_func(void) 3.229 -{ 3.230 - glMatrixMode(GL_MODELVIEW); 3.231 - glPushMatrix(); 3.232 - glTranslatef(-0.9, -0.9, 0); 3.233 - glScalef(0.5, 0.1, 1); 3.234 - 3.235 - glBindTexture(GL_TEXTURE_1D, xfer_tex); 3.236 - glEnable(GL_TEXTURE_1D); 3.237 - 3.238 - glBegin(GL_QUADS); 3.239 - glColor3f(1, 1, 1); 3.240 - glTexCoord1f(1); 3.241 - glVertex2f(1, 0); 3.242 - glVertex2f(1, 1); 3.243 - glTexCoord1f(0); 3.244 - glVertex2f(0, 1); 3.245 - glVertex2f(0, 0); 3.246 - glEnd(); 3.247 - 3.248 - glDisable(GL_TEXTURE_1D); 3.249 - 3.250 - glLineWidth(2.0); 3.251 - glBegin(GL_LINE_LOOP); 3.252 - if(uimode == UIMODE_XFER) { 3.253 - glColor3f(1, 0, 0); 3.254 - } else { 3.255 - glColor3f(0, 0, 1); 3.256 - } 3.257 - glVertex2f(0, 0); 3.258 - glVertex2f(1, 0); 3.259 - glVertex2f(1, 1); 3.260 - glVertex2f(0, 1); 3.261 - glEnd(); 3.262 - 3.263 - glPopMatrix(); 3.264 -} 3.265 - 3.266 -void reshape(int x, int y) 3.267 -{ 3.268 - glViewport(0, 0, x, y); 3.269 - 3.270 - if(x != win_xsz || y != win_ysz) { 3.271 - raytex_needs_recalc = 1; 3.272 - win_xsz = x; 3.273 - win_ysz = y; 3.274 - } 3.275 -} 3.276 - 3.277 -void keyb(unsigned char key, int x, int y) 3.278 -{ 3.279 - switch(key) { 3.280 - case 27: 3.281 - exit(0); 3.282 - 3.283 - case 'x': 3.284 - uimode = UIMODE_XFER; 3.285 - glutPostRedisplay(); 3.286 - break; 3.287 - 3.288 - case 'c': 3.289 - uimode = UIMODE_CURSOR; 3.290 - glutPostRedisplay(); 3.291 - break; 3.292 - 3.293 - default: 3.294 - break; 3.295 - } 3.296 -} 3.297 - 3.298 -void keyb_up(unsigned char key, int x, int y) 3.299 -{ 3.300 - switch(key) { 3.301 - case 'x': 3.302 - if(uimode == UIMODE_XFER) { 3.303 - uimode = UIMODE_DEFAULT; 3.304 - glutPostRedisplay(); 3.305 - } 3.306 - break; 3.307 - 3.308 - case 'c': 3.309 - if(uimode == UIMODE_CURSOR) { 3.310 - uimode = UIMODE_DEFAULT; 3.311 - glutPostRedisplay(); 3.312 - } 3.313 - break; 3.314 - 3.315 - default: 3.316 - break; 3.317 - } 3.318 -} 3.319 - 3.320 -static int bnstate[32]; 3.321 -static int prev_x, prev_y; 3.322 - 3.323 -void mouse(int bn, int state, int x, int y) 3.324 -{ 3.325 - bnstate[bn - GLUT_LEFT_BUTTON] = state == GLUT_DOWN; 3.326 - prev_x = x; 3.327 - prev_y = y; 3.328 -} 3.329 - 3.330 -void motion(int x, int y) 3.331 -{ 3.332 - int dx = x - prev_x; 3.333 - int dy = y - prev_y; 3.334 - prev_x = x; 3.335 - prev_y = y; 3.336 - 3.337 - switch(uimode) { 3.338 - case UIMODE_XFER: 3.339 - if(dx || dy) { 3.340 - xfer_mean += dx / (float)win_xsz; 3.341 - xfer_sdev += 0.5 * dy / (float)win_ysz; 3.342 - 3.343 - xfer_mean = xfer_mean < 0.0 ? 0.0 : (xfer_mean > 1.0 ? 1.0 : xfer_mean); 3.344 - xfer_sdev = xfer_sdev < 0.0 ? 0.0 : (xfer_sdev > 1.0 ? 1.0 : xfer_sdev); 3.345 - 3.346 - xfertex_needs_recalc = 1; 3.347 - glutPostRedisplay(); 3.348 - } 3.349 - break; 3.350 - 3.351 - case UIMODE_CURSOR: 3.352 - cur_z += 0.5 * dy / (float)win_ysz; 3.353 - 3.354 - if(cur_z < 0.0) 3.355 - cur_z = 0.0; 3.356 - if(cur_z > 1.0) 3.357 - cur_z = 1.0; 3.358 - 3.359 - set_uniform_float(vol_sdr, "zclip", cur_z); 3.360 - glutPostRedisplay(); 3.361 - break; 3.362 - 3.363 - default: 3.364 - /* view control */ 3.365 - if(bnstate[0]) { 3.366 - cam_theta += dx * 0.5; 3.367 - cam_phi += dy * 0.5; 3.368 - 3.369 - if(cam_phi <= -90) cam_phi = -89; 3.370 - if(cam_phi >= 90) cam_phi = 89; 3.371 - 3.372 - glutPostRedisplay(); 3.373 - } 3.374 - 3.375 - if(bnstate[1]) { 3.376 - cam_x += dx * 0.025; 3.377 - cam_y += dy * 0.025; 3.378 - glutPostRedisplay(); 3.379 - } 3.380 - 3.381 - if(bnstate[2]) { 3.382 - cam_dist += dy * 0.025; 3.383 - if(cam_dist < 0.0) cam_dist = 0.0; 3.384 - glutPostRedisplay(); 3.385 - } 3.386 - } 3.387 -} 3.388 - 3.389 - 3.390 -int parse_args(int argc, char **argv) 3.391 -{ 3.392 - int i; 3.393 - char *endp; 3.394 - 3.395 - for(i=1; i<argc; i++) { 3.396 - if(argv[i][0] == '-' && argv[i][2] == 0) { 3.397 - switch(argv[i][1]) { 3.398 - case 'm': 3.399 - xfer_mean = strtod(argv[++i], &endp); 3.400 - if(endp == argv[i]) { 3.401 - fprintf(stderr, "-m must be followed by the transfer function mean\n"); 3.402 - return -1; 3.403 - } 3.404 - break; 3.405 - 3.406 - case 'd': 3.407 - xfer_sdev = strtod(argv[++i], &endp); 3.408 - if(endp == argv[i]) { 3.409 - fprintf(stderr, "-d must be followed by the transfer function std.deviation\n"); 3.410 - return -1; 3.411 - } 3.412 - break; 3.413 - 3.414 - default: 3.415 - fprintf(stderr, "unrecognized option: %s\n", argv[i]); 3.416 - return -1; 3.417 - } 3.418 - } else { 3.419 - if(fname) { 3.420 - fprintf(stderr, "unexpected argument: %s\n", argv[i]); 3.421 - return -1; 3.422 - } 3.423 - fname = argv[i]; 3.424 - } 3.425 - } 3.426 - 3.427 - if(!fname) { 3.428 - fprintf(stderr, "pass the volume descriptor filename\n"); 3.429 - return -1; 3.430 - } 3.431 - return 0; 3.432 -} 3.433 - 3.434 - 3.435 -static void create_ray_texture(int xsz, int ysz, float vfov, vec2_t *tex_scale) 3.436 -{ 3.437 - int i, j; 3.438 - int cur_tex_xsz, cur_tex_ysz; 3.439 - int tex_xsz = round_pow2(xsz); 3.440 - int tex_ysz = round_pow2(ysz); 3.441 - float *teximg, *dir; 3.442 - 3.443 - if(!(teximg = malloc(3 * xsz * ysz * sizeof *teximg))) { 3.444 - return; 3.445 - } 3.446 - dir = teximg; 3.447 - 3.448 - for(i=0; i<ysz; i++) { 3.449 - for(j=0; j<xsz; j++) { 3.450 - vec3_t rdir = get_primary_ray_dir(j, i, xsz, ysz, vfov); 3.451 - *dir++ = rdir.x; 3.452 - *dir++ = rdir.y; 3.453 - *dir++ = rdir.z; 3.454 - } 3.455 - } 3.456 - 3.457 - if(!ray_tex) { 3.458 - glGenTextures(1, &ray_tex); 3.459 - } 3.460 - 3.461 - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cur_tex_xsz); 3.462 - glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cur_tex_ysz); 3.463 - 3.464 - if(tex_xsz > cur_tex_xsz || tex_ysz > cur_tex_ysz) { 3.465 - glBindTexture(GL_TEXTURE_2D, ray_tex); 3.466 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 3.467 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 3.468 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 3.469 - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 3.470 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F_ARB, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, 0); 3.471 - } 3.472 - 3.473 - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, xsz, ysz, GL_RGB, GL_FLOAT, teximg); 3.474 - free(teximg); 3.475 - 3.476 - if(tex_scale) { 3.477 - tex_scale->x = (float)xsz / (float)tex_xsz; 3.478 - tex_scale->y = (float)ysz / (float)tex_ysz; 3.479 - } 3.480 - raytex_needs_recalc = 0; 3.481 -} 3.482 - 3.483 -static vec3_t get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg) 3.484 -{ 3.485 - float vfov = M_PI * vfov_deg / 180.0; 3.486 - float aspect = (float)w / (float)h; 3.487 - 3.488 - float ysz = 2.0; 3.489 - float xsz = aspect * ysz; 3.490 - 3.491 - float px = ((float)x / (float)w) * xsz - xsz / 2.0; 3.492 - float py = 1.0 - ((float)y / (float)h) * ysz; 3.493 - float pz = 1.0 / tan(0.5 * vfov); 3.494 - 3.495 - float mag = sqrt(px * px + py * py + pz * pz); 3.496 - 3.497 - return v3_cons(px / mag, py / mag, pz / mag); 3.498 -} 3.499 - 3.500 -static int round_pow2(int x) 3.501 -{ 3.502 - x--; 3.503 - x = (x >> 1) | x; 3.504 - x = (x >> 2) | x; 3.505 - x = (x >> 4) | x; 3.506 - x = (x >> 8) | x; 3.507 - x = (x >> 16) | x; 3.508 - return x + 1; 3.509 -} 3.510 - 3.511 -static void create_transfer_map(float mean, float sdev) 3.512 -{ 3.513 - static float map[XFER_MAP_SZ]; 3.514 - int i; 3.515 - 3.516 - if(!xfer_tex) { 3.517 - glGenTextures(1, &xfer_tex); 3.518 - glBindTexture(GL_TEXTURE_1D, xfer_tex); 3.519 - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 3.520 - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 3.521 - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 3.522 - glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 3.523 - glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE32F_ARB, XFER_MAP_SZ, 0, GL_LUMINANCE, GL_FLOAT, 0); 3.524 - } 3.525 - 3.526 - for(i=0; i<XFER_MAP_SZ; i++) { 3.527 - float x = (float)i / (float)(XFER_MAP_SZ - 1); 3.528 - map[i] = gaussian(x, mean, sdev) - 1.0; 3.529 - } 3.530 - putchar('\n'); 3.531 - 3.532 - glTexSubImage1D(GL_TEXTURE_1D, 0, 0, XFER_MAP_SZ, GL_LUMINANCE, GL_FLOAT, map); 3.533 - xfertex_needs_recalc = 0; 3.534 -}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/volray.cc Mon Apr 09 23:42:57 2012 +0300 4.3 @@ -0,0 +1,490 @@ 4.4 +#include <stdio.h> 4.5 +#include <stdlib.h> 4.6 +#include <assert.h> 4.7 + 4.8 +#include <GL/glew.h> 4.9 +#ifndef __APPLE__ 4.10 +#include <GL/glut.h> 4.11 +#else 4.12 +#include <GLUT/glut.h> 4.13 +#endif 4.14 + 4.15 +#include <vmath/vmath.h> 4.16 +#include <imago2.h> 4.17 +#include "sdr.h" 4.18 +#include "volume.h" 4.19 + 4.20 +#define XFER_MAP_SZ 512 4.21 + 4.22 +static void render_volume(); 4.23 +static void draw_slice(); 4.24 +static void draw_xfer_func(); 4.25 + 4.26 +/* 4.27 +void keyb(unsigned char key, int x, int y); 4.28 +void keyb_up(unsigned char key, int x, int y); 4.29 +void mouse(int bn, int state, int x, int y); 4.30 +void motion(int x, int y); 4.31 +int parse_args(int argc, char **argv); 4.32 +*/ 4.33 + 4.34 +static void create_ray_texture(int xsz, int ysz, float vfov, Vector2 *tex_scale); 4.35 +static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg); 4.36 +static int round_pow2(int x); 4.37 +static void create_transfer_map(float mean, float sdev); 4.38 + 4.39 +static float cam_theta = 0, cam_phi = 0, cam_dist = 4.0; 4.40 +static float cam_x, cam_y, cam_z; 4.41 + 4.42 +static vec2_t tex_scale; 4.43 +static unsigned int vol_sdr, slice_sdr, ray_tex; 4.44 +static int win_xsz, win_ysz; 4.45 +static bool raytex_needs_recalc = true; 4.46 + 4.47 +static unsigned int xfer_tex; 4.48 +static float xfer_mean = 0.7, xfer_sdev = 0.1; 4.49 +static bool xfertex_needs_recalc = true; 4.50 + 4.51 +static float cur_z = 0.0; 4.52 +static float ray_step = 0.01; 4.53 + 4.54 +static Volume volume; 4.55 + 4.56 + 4.57 +bool volray_init() 4.58 +{ 4.59 + glewInit(); 4.60 + 4.61 + if(!(vol_sdr = create_program_load("sdr/volray.v.glsl", "sdr/volray.p.glsl"))) { 4.62 + return false; 4.63 + } 4.64 + set_uniform_int(vol_sdr, "volume", 0); 4.65 + set_uniform_int(vol_sdr, "ray_tex", 1); 4.66 + set_uniform_int(vol_sdr, "xfer_tex", 2); 4.67 + set_uniform_float(vol_sdr, "ray_step", ray_step); 4.68 + set_uniform_float(vol_sdr, "zclip", cur_z); 4.69 + 4.70 + if(!(slice_sdr = create_program_load(0, "sdr/slice.p.glsl"))) { 4.71 + return false; 4.72 + } 4.73 + set_uniform_int(slice_sdr, "volume", 0); 4.74 + set_uniform_int(slice_sdr, "xfer_tex", 1); 4.75 + 4.76 + if(!volume.load(fname)) { 4.77 + return false; 4.78 + } 4.79 + return true; 4.80 +} 4.81 + 4.82 +void volray_draw(void) 4.83 +{ 4.84 + /* recalculate primary ray texture if needed */ 4.85 + if(raytex_needs_recalc) { 4.86 + create_ray_texture(win_xsz, win_ysz, 50.0, &tex_scale); 4.87 + } 4.88 + /* recalculate transfer function texture if needed */ 4.89 + if(xfertex_needs_recalc) { 4.90 + create_transfer_map(xfer_mean, xfer_sdev); 4.91 + } 4.92 + 4.93 + render_volume(); 4.94 + draw_slice(); 4.95 + draw_xfer_func(); 4.96 + 4.97 + assert(glGetError() == GL_NO_ERROR); 4.98 +} 4.99 + 4.100 +static void render_volume(void) 4.101 +{ 4.102 + /* set the camera transformation */ 4.103 + glMatrixMode(GL_MODELVIEW); 4.104 + glPushMatrix(); 4.105 + glLoadIdentity(); 4.106 + glRotatef(-90, 1, 0, 0); 4.107 + glTranslatef(cam_x, cam_y, -cam_z); 4.108 + glRotatef(cam_theta, 0, 1, 0); 4.109 + glRotatef(cam_phi, 1, 0, 0); 4.110 + glTranslatef(0, 0, -cam_dist); 4.111 + 4.112 + /* setup the texture matrix to map the useful part of the ray texture to [0,1] */ 4.113 + glMatrixMode(GL_TEXTURE); 4.114 + glPushMatrix(); 4.115 + glLoadIdentity(); 4.116 + glScalef(tex_scale.x, tex_scale.y, 1.0); 4.117 + 4.118 + /* tex unit0: volume data 3D texture */ 4.119 + glActiveTexture(GL_TEXTURE0); 4.120 + glBindTexture(GL_TEXTURE_3D, volume.get_texture()); 4.121 + glEnable(GL_TEXTURE_3D); 4.122 + 4.123 + /* tex unit1: primary rays in view space */ 4.124 + glActiveTexture(GL_TEXTURE1); 4.125 + glBindTexture(GL_TEXTURE_2D, ray_tex); 4.126 + glEnable(GL_TEXTURE_2D); 4.127 + 4.128 + /* tex unit2: transfer function (1d) */ 4.129 + glActiveTexture(GL_TEXTURE2); 4.130 + glBindTexture(GL_TEXTURE_1D, xfer_tex); 4.131 + glEnable(GL_TEXTURE_1D); 4.132 + 4.133 + bind_program(vol_sdr); 4.134 + glBegin(GL_QUADS); 4.135 + glColor3f(1, 1, 1); 4.136 + glTexCoord2f(0, 1); glVertex2f(-1, -1); 4.137 + glTexCoord2f(1, 1); glVertex2f(1, -1); 4.138 + glTexCoord2f(1, 0); glVertex2f(1, 1); 4.139 + glTexCoord2f(0, 0); glVertex2f(-1, 1); 4.140 + glEnd(); 4.141 + bind_program(0); 4.142 + 4.143 + glActiveTexture(GL_TEXTURE2); 4.144 + glDisable(GL_TEXTURE_1D); 4.145 + glActiveTexture(GL_TEXTURE1); 4.146 + glDisable(GL_TEXTURE_2D); 4.147 + glActiveTexture(GL_TEXTURE0); 4.148 + glDisable(GL_TEXTURE_3D); 4.149 + 4.150 + glMatrixMode(GL_TEXTURE); 4.151 + glPopMatrix(); 4.152 + glMatrixMode(GL_MODELVIEW); 4.153 + glPopMatrix(); 4.154 +} 4.155 + 4.156 +static void draw_slice(void) 4.157 +{ 4.158 + glMatrixMode(GL_MODELVIEW); 4.159 + glPushMatrix(); 4.160 + glTranslatef(0.9, 0.9, 0); 4.161 + glScalef(0.3, 0.3 * ((float)win_xsz / win_ysz), 1); 4.162 + glTranslatef(-1, -1, 0); 4.163 + 4.164 + glActiveTexture(GL_TEXTURE0); 4.165 + glBindTexture(GL_TEXTURE_3D, volume.get_texture()); 4.166 + glEnable(GL_TEXTURE_3D); 4.167 + 4.168 + glActiveTexture(GL_TEXTURE1); 4.169 + glBindTexture(GL_TEXTURE_1D, xfer_tex); 4.170 + glEnable(GL_TEXTURE_1D); 4.171 + 4.172 + bind_program(slice_sdr); 4.173 + 4.174 + glBegin(GL_QUADS); 4.175 + glColor3f(1, 1, 1); 4.176 + glTexCoord3f(0, 1, cur_z); glVertex2f(-1, -1); 4.177 + glTexCoord3f(1, 1, cur_z); glVertex2f(1, -1); 4.178 + glTexCoord3f(1, 0, cur_z); glVertex2f(1, 1); 4.179 + glTexCoord3f(0, 0, cur_z); glVertex2f(-1, 1); 4.180 + glEnd(); 4.181 + 4.182 + bind_program(0); 4.183 + 4.184 + glActiveTexture(GL_TEXTURE1); 4.185 + glDisable(GL_TEXTURE_1D); 4.186 + glActiveTexture(GL_TEXTURE0); 4.187 + glDisable(GL_TEXTURE_3D); 4.188 + glPopMatrix(); 4.189 +} 4.190 + 4.191 +static void draw_xfer_func(void) 4.192 +{ 4.193 + glMatrixMode(GL_MODELVIEW); 4.194 + glPushMatrix(); 4.195 + glTranslatef(-0.9, -0.9, 0); 4.196 + glScalef(0.5, 0.1, 1); 4.197 + 4.198 + glBindTexture(GL_TEXTURE_1D, xfer_tex); 4.199 + glEnable(GL_TEXTURE_1D); 4.200 + 4.201 + glBegin(GL_QUADS); 4.202 + glColor3f(1, 1, 1); 4.203 + glTexCoord1f(1); 4.204 + glVertex2f(1, 0); 4.205 + glVertex2f(1, 1); 4.206 + glTexCoord1f(0); 4.207 + glVertex2f(0, 1); 4.208 + glVertex2f(0, 0); 4.209 + glEnd(); 4.210 + 4.211 + glDisable(GL_TEXTURE_1D); 4.212 + 4.213 + glLineWidth(2.0); 4.214 + glBegin(GL_LINE_LOOP); 4.215 + if(uimode == UIMODE_XFER) { 4.216 + glColor3f(1, 0, 0); 4.217 + } else { 4.218 + glColor3f(0, 0, 1); 4.219 + } 4.220 + glVertex2f(0, 0); 4.221 + glVertex2f(1, 0); 4.222 + glVertex2f(1, 1); 4.223 + glVertex2f(0, 1); 4.224 + glEnd(); 4.225 + 4.226 + glPopMatrix(); 4.227 +} 4.228 + 4.229 +void volray_resize(int x, int y) 4.230 +{ 4.231 + glViewport(0, 0, x, y); 4.232 + 4.233 + if(x != win_xsz || y != win_ysz) { 4.234 + raytex_needs_recalc = true; 4.235 + win_xsz = x; 4.236 + win_ysz = y; 4.237 + } 4.238 +} 4.239 + 4.240 +#if 0 4.241 +void keyb(unsigned char key, int x, int y) 4.242 +{ 4.243 + switch(key) { 4.244 + case 27: 4.245 + exit(0); 4.246 + 4.247 + case 'x': 4.248 + uimode = UIMODE_XFER; 4.249 + glutPostRedisplay(); 4.250 + break; 4.251 + 4.252 + case 'c': 4.253 + uimode = UIMODE_CURSOR; 4.254 + glutPostRedisplay(); 4.255 + break; 4.256 + 4.257 + default: 4.258 + break; 4.259 + } 4.260 +} 4.261 + 4.262 +void keyb_up(unsigned char key, int x, int y) 4.263 +{ 4.264 + switch(key) { 4.265 + case 'x': 4.266 + if(uimode == UIMODE_XFER) { 4.267 + uimode = UIMODE_DEFAULT; 4.268 + glutPostRedisplay(); 4.269 + } 4.270 + break; 4.271 + 4.272 + case 'c': 4.273 + if(uimode == UIMODE_CURSOR) { 4.274 + uimode = UIMODE_DEFAULT; 4.275 + glutPostRedisplay(); 4.276 + } 4.277 + break; 4.278 + 4.279 + default: 4.280 + break; 4.281 + } 4.282 +} 4.283 + 4.284 +static int bnstate[32]; 4.285 +static int prev_x, prev_y; 4.286 + 4.287 +void mouse(int bn, int state, int x, int y) 4.288 +{ 4.289 + bnstate[bn - GLUT_LEFT_BUTTON] = state == GLUT_DOWN; 4.290 + prev_x = x; 4.291 + prev_y = y; 4.292 +} 4.293 + 4.294 +void motion(int x, int y) 4.295 +{ 4.296 + int dx = x - prev_x; 4.297 + int dy = y - prev_y; 4.298 + prev_x = x; 4.299 + prev_y = y; 4.300 + 4.301 + switch(uimode) { 4.302 + case UIMODE_XFER: 4.303 + if(dx || dy) { 4.304 + xfer_mean += dx / (float)win_xsz; 4.305 + xfer_sdev += 0.5 * dy / (float)win_ysz; 4.306 + 4.307 + xfer_mean = xfer_mean < 0.0 ? 0.0 : (xfer_mean > 1.0 ? 1.0 : xfer_mean); 4.308 + xfer_sdev = xfer_sdev < 0.0 ? 0.0 : (xfer_sdev > 1.0 ? 1.0 : xfer_sdev); 4.309 + 4.310 + xfertex_needs_recalc = true; 4.311 + glutPostRedisplay(); 4.312 + } 4.313 + break; 4.314 + 4.315 + case UIMODE_CURSOR: 4.316 + cur_z += 0.5 * dy / (float)win_ysz; 4.317 + 4.318 + if(cur_z < 0.0) 4.319 + cur_z = 0.0; 4.320 + if(cur_z > 1.0) 4.321 + cur_z = 1.0; 4.322 + 4.323 + set_uniform_float(vol_sdr, "zclip", cur_z); 4.324 + glutPostRedisplay(); 4.325 + break; 4.326 + 4.327 + default: 4.328 + /* view control */ 4.329 + if(bnstate[0]) { 4.330 + cam_theta += dx * 0.5; 4.331 + cam_phi += dy * 0.5; 4.332 + 4.333 + if(cam_phi <= -90) cam_phi = -89; 4.334 + if(cam_phi >= 90) cam_phi = 89; 4.335 + 4.336 + glutPostRedisplay(); 4.337 + } 4.338 + 4.339 + if(bnstate[1]) { 4.340 + cam_x += dx * 0.025; 4.341 + cam_y += dy * 0.025; 4.342 + glutPostRedisplay(); 4.343 + } 4.344 + 4.345 + if(bnstate[2]) { 4.346 + cam_dist += dy * 0.025; 4.347 + if(cam_dist < 0.0) cam_dist = 0.0; 4.348 + glutPostRedisplay(); 4.349 + } 4.350 + } 4.351 +} 4.352 + 4.353 + 4.354 +int parse_args(int argc, char **argv) 4.355 +{ 4.356 + int i; 4.357 + char *endp; 4.358 + 4.359 + for(i=1; i<argc; i++) { 4.360 + if(argv[i][0] == '-' && argv[i][2] == 0) { 4.361 + switch(argv[i][1]) { 4.362 + case 'm': 4.363 + xfer_mean = strtod(argv[++i], &endp); 4.364 + if(endp == argv[i]) { 4.365 + fprintf(stderr, "-m must be followed by the transfer function mean\n"); 4.366 + return -1; 4.367 + } 4.368 + break; 4.369 + 4.370 + case 'd': 4.371 + xfer_sdev = strtod(argv[++i], &endp); 4.372 + if(endp == argv[i]) { 4.373 + fprintf(stderr, "-d must be followed by the transfer function std.deviation\n"); 4.374 + return -1; 4.375 + } 4.376 + break; 4.377 + 4.378 + default: 4.379 + fprintf(stderr, "unrecognized option: %s\n", argv[i]); 4.380 + return -1; 4.381 + } 4.382 + } else { 4.383 + if(fname) { 4.384 + fprintf(stderr, "unexpected argument: %s\n", argv[i]); 4.385 + return -1; 4.386 + } 4.387 + fname = argv[i]; 4.388 + } 4.389 + } 4.390 + 4.391 + if(!fname) { 4.392 + fprintf(stderr, "pass the volume descriptor filename\n"); 4.393 + return -1; 4.394 + } 4.395 + return 0; 4.396 +} 4.397 +#endif 4.398 + 4.399 + 4.400 +static void create_ray_texture(int xsz, int ysz, float vfov, Vector2 *tex_scale) 4.401 +{ 4.402 + int cur_tex_xsz, cur_tex_ysz; 4.403 + int tex_xsz = round_pow2(xsz); 4.404 + int tex_ysz = round_pow2(ysz); 4.405 + float *teximg, *dir; 4.406 + 4.407 + teximg = new float[3 * xsz * ysz]; 4.408 + dir = teximg; 4.409 + 4.410 + for(int i=0; i<ysz; i++) { 4.411 + for(int j=0; j<xsz; j++) { 4.412 + Vector3 rdir = get_primary_ray_dir(j, i, xsz, ysz, vfov); 4.413 + *dir++ = rdir.x; 4.414 + *dir++ = rdir.y; 4.415 + *dir++ = rdir.z; 4.416 + } 4.417 + } 4.418 + 4.419 + if(!ray_tex) { 4.420 + glGenTextures(1, &ray_tex); 4.421 + } 4.422 + 4.423 + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &cur_tex_xsz); 4.424 + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &cur_tex_ysz); 4.425 + 4.426 + if(tex_xsz > cur_tex_xsz || tex_ysz > cur_tex_ysz) { 4.427 + glBindTexture(GL_TEXTURE_2D, ray_tex); 4.428 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 4.429 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 4.430 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 4.431 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 4.432 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F_ARB, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, 0); 4.433 + } 4.434 + 4.435 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, xsz, ysz, GL_RGB, GL_FLOAT, teximg); 4.436 + delete [] teximg; 4.437 + 4.438 + if(tex_scale) { 4.439 + tex_scale->x = (float)xsz / (float)tex_xsz; 4.440 + tex_scale->y = (float)ysz / (float)tex_ysz; 4.441 + } 4.442 + raytex_needs_recalc = false; 4.443 +} 4.444 + 4.445 +static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg) 4.446 +{ 4.447 + float vfov = M_PI * vfov_deg / 180.0; 4.448 + float aspect = (float)w / (float)h; 4.449 + 4.450 + float ysz = 2.0; 4.451 + float xsz = aspect * ysz; 4.452 + 4.453 + float px = ((float)x / (float)w) * xsz - xsz / 2.0; 4.454 + float py = 1.0 - ((float)y / (float)h) * ysz; 4.455 + float pz = 1.0 / tan(0.5 * vfov); 4.456 + 4.457 + float mag = sqrt(px * px + py * py + pz * pz); 4.458 + return Vector3(px / mag, py / mag, pz / mag); 4.459 +} 4.460 + 4.461 +static int round_pow2(int x) 4.462 +{ 4.463 + x--; 4.464 + x = (x >> 1) | x; 4.465 + x = (x >> 2) | x; 4.466 + x = (x >> 4) | x; 4.467 + x = (x >> 8) | x; 4.468 + x = (x >> 16) | x; 4.469 + return x + 1; 4.470 +} 4.471 + 4.472 +static void create_transfer_map(float mean, float sdev) 4.473 +{ 4.474 + static float map[XFER_MAP_SZ]; 4.475 + 4.476 + if(!xfer_tex) { 4.477 + glGenTextures(1, &xfer_tex); 4.478 + glBindTexture(GL_TEXTURE_1D, xfer_tex); 4.479 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 4.480 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 4.481 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 4.482 + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 4.483 + glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE32F_ARB, XFER_MAP_SZ, 0, GL_LUMINANCE, GL_FLOAT, 0); 4.484 + } 4.485 + 4.486 + for(int i=0; i<XFER_MAP_SZ; i++) { 4.487 + float x = (float)i / (float)(XFER_MAP_SZ - 1); 4.488 + map[i] = gaussian(x, mean, sdev) - 1.0; 4.489 + } 4.490 + 4.491 + glTexSubImage1D(GL_TEXTURE_1D, 0, 0, XFER_MAP_SZ, GL_LUMINANCE, GL_FLOAT, map); 4.492 + xfertex_needs_recalc = false; 4.493 +}
5.1 --- a/src/volume.c Sun Apr 08 14:31:03 2012 +0300 5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 5.3 @@ -1,252 +0,0 @@ 5.4 -#include <stdio.h> 5.5 -#include <stdlib.h> 5.6 -#include <string.h> 5.7 -#include <ctype.h> 5.8 - 5.9 -#ifndef __APPLE__ 5.10 -#include <GL/gl.h> 5.11 -#else 5.12 -#include <OpenGL/gl.h> 5.13 -#endif 5.14 - 5.15 -#include <imago2.h> 5.16 -#include "volume.h" 5.17 - 5.18 -struct slice { 5.19 - char *name; 5.20 - struct slice *next; 5.21 -}; 5.22 - 5.23 -static void calc_gradients(float *voxels, int xsz, int ysz, int zsz); 5.24 -static struct slice *read_voldesc(const char *fname, struct volume *vol); 5.25 -static char *trim(char *str); 5.26 - 5.27 -struct volume *load_volume(const char *fname) 5.28 -{ 5.29 - int i; 5.30 - struct slice *slist; 5.31 - struct volume *vol = 0; 5.32 - float *voxels = 0, *vptr; 5.33 - struct img_pixmap img; 5.34 - 5.35 - if(!(vol = malloc(sizeof *vol))) { 5.36 - perror("failed to allocate volume"); 5.37 - return 0; 5.38 - } 5.39 - memset(vol, 0, sizeof *vol); 5.40 - vol->zaspect = 1; 5.41 - 5.42 - if(!(slist = read_voldesc(fname, vol))) { 5.43 - goto err; 5.44 - } 5.45 - 5.46 - /* load the first image to determine slice dimensions */ 5.47 - img_init(&img); 5.48 - if(img_load(&img, slist->name) == -1) { 5.49 - fprintf(stderr, "failed to load volume slice: %s\n", slist->name); 5.50 - goto err; 5.51 - } 5.52 - 5.53 - vol->sz[0] = img.width; 5.54 - vol->sz[1] = img.height; 5.55 - printf("volume dimensions: %dx%dx%d\n", img.width, img.height, vol->sz[2]); 5.56 - 5.57 - /* allocate the whole volume at once */ 5.58 - if(!(voxels = malloc(vol->sz[0] * vol->sz[1] * vol->sz[2] * 4 * sizeof *voxels))) { 5.59 - img_destroy(&img); 5.60 - goto err; 5.61 - } 5.62 - vptr = voxels; 5.63 - img_destroy(&img); 5.64 - 5.65 - /* put the volume data into the alpha component */ 5.66 - for(i=0; i<vol->sz[2]; i++) { 5.67 - int x, y, xsz, ysz; 5.68 - float *pixels, *src; 5.69 - struct slice *slice = slist; 5.70 - slist = slist->next; 5.71 - 5.72 - if(!(pixels = img_load_pixels(slice->name, &xsz, &ysz, IMG_FMT_GREYF))) { 5.73 - fprintf(stderr, "failed to load volume slice: %s\n", slice->name); 5.74 - goto err; 5.75 - } 5.76 - 5.77 - if(xsz != vol->sz[0] || ysz != vol->sz[1]) { 5.78 - fprintf(stderr, "inconsistent dimensions for slice %s: %dx%d (%dx%d expected)\n", 5.79 - slice->name, xsz, ysz, vol->sz[0], vol->sz[1]); 5.80 - goto err; 5.81 - } 5.82 - free(slice->name); 5.83 - free(slice); 5.84 - 5.85 - src = pixels; 5.86 - for(y=0; y<ysz; y++) { 5.87 - for(x=0; x<xsz; x++) { 5.88 - vptr[0] = vptr[1] = vptr[2] = 0.0f; 5.89 - vptr[3] = *src++; 5.90 - vptr += 4; 5.91 - } 5.92 - } 5.93 - img_free_pixels(pixels); 5.94 - } 5.95 - 5.96 - /* calculate gradients */ 5.97 - calc_gradients(voxels, vol->sz[0], vol->sz[1], vol->sz[2]); 5.98 - 5.99 - /* create the volume texture */ 5.100 - glGenTextures(1, &vol->tex_vol); 5.101 - glBindTexture(GL_TEXTURE_3D, vol->tex_vol); 5.102 - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 5.103 - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 5.104 - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 5.105 - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 5.106 - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 5.107 - glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F_ARB, vol->sz[0], vol->sz[1], vol->sz[2], 0, 5.108 - GL_RGBA, GL_FLOAT, voxels); 5.109 - 5.110 - /* ... and destroy our copy */ 5.111 - free(voxels); 5.112 - return vol; 5.113 - 5.114 -err: 5.115 - while(slist) { 5.116 - struct slice *tmp = slist; 5.117 - slist = slist->next; 5.118 - free(tmp->name); 5.119 - free(tmp); 5.120 - } 5.121 - free_volume(vol); 5.122 - free(voxels); 5.123 - return 0; 5.124 -} 5.125 - 5.126 -void free_volume(struct volume *vol) 5.127 -{ 5.128 - if(vol) { 5.129 - if(vol->tex_vol) { 5.130 - glDeleteTextures(1, &vol->tex_vol); 5.131 - } 5.132 - free(vol); 5.133 - } 5.134 -} 5.135 - 5.136 -struct vec4 { float x, y, z, w; }; 5.137 - 5.138 -static void calc_gradients(float *voxels, int xsz, int ysz, int zsz) 5.139 -{ 5.140 - int x, y, z, slice_pixels = xsz * ysz; 5.141 - struct vec4 *vptr = (struct vec4*)voxels; 5.142 - 5.143 - for(z=0; z<zsz; z++) { 5.144 - for(y=0; y<ysz; y++) { 5.145 - for(x=0; x<xsz; x++) { 5.146 - float x0, x1, y0, y1, z0, z1; 5.147 - 5.148 - x0 = x > 0 ? (vptr - 1)->w : vptr->w; 5.149 - y0 = y > 0 ? (vptr - xsz)->w : vptr->w; 5.150 - z0 = z > 0 ? (vptr - slice_pixels)->w : vptr->w; 5.151 - x1 = x < xsz - 1 ? (vptr + 1)->w : vptr->w; 5.152 - y1 = y < ysz - 1 ? (vptr + xsz)->w : vptr->w; 5.153 - z1 = z < zsz - 1 ? (vptr + slice_pixels)->w : vptr->w; 5.154 - 5.155 - vptr->x = x1 - x0; 5.156 - vptr->y = y1 - y0; 5.157 - vptr->z = z1 - z0; 5.158 - 5.159 - vptr++; 5.160 - } 5.161 - } 5.162 - } 5.163 -} 5.164 - 5.165 -static struct slice *read_voldesc(const char *fname, struct volume *vol) 5.166 -{ 5.167 - FILE *fp = 0; 5.168 - char buf[512], *slash, *prefix = ""; 5.169 - int mode_slices = 0; 5.170 - struct slice *head = 0, *tail; 5.171 - 5.172 - if(!(fp = fopen(fname, "r"))) { 5.173 - fprintf(stderr, "failed to open volume descriptor: %s\n", fname); 5.174 - return 0; 5.175 - } 5.176 - fgets(buf, sizeof buf, fp); 5.177 - if(strstr(buf, "VOLDESC") != buf) { 5.178 - fprintf(stderr, "invalid file format while trying to read volume descriptor: %s\n", fname); 5.179 - goto err; 5.180 - } 5.181 - 5.182 - if((slash = strrchr(fname, '/'))) { 5.183 - int len = slash - fname + 1; 5.184 - prefix = alloca(len + 1); 5.185 - memcpy(prefix, fname, len); 5.186 - prefix[len] = 0; 5.187 - } 5.188 - 5.189 - while(fgets(buf, sizeof buf, fp)) { 5.190 - char *line = trim(buf); 5.191 - 5.192 - if(!*line || *line == '#') 5.193 - continue; 5.194 - 5.195 - if(mode_slices) { 5.196 - /* we're in the part that contains filenames... append to the list */ 5.197 - struct slice *node = malloc(sizeof *node); 5.198 - if(!node || !(node->name = malloc(strlen(prefix) + strlen(line) + 1))) { 5.199 - perror("failed to allocate list node"); 5.200 - free(node); 5.201 - goto err; 5.202 - } 5.203 - sprintf(node->name, "%s%s", prefix, line); 5.204 - node->next = 0; 5.205 - 5.206 - if(head) { 5.207 - tail->next = node; 5.208 - tail = node; 5.209 - } else { 5.210 - head = tail = node; 5.211 - } 5.212 - vol->sz[2]++; 5.213 - } else { 5.214 - /* TODO we're in the options part... parse */ 5.215 - 5.216 - if(strcmp(line, "SLICES") == 0) { 5.217 - mode_slices = 1; 5.218 - } 5.219 - } 5.220 - } 5.221 - fclose(fp); 5.222 - 5.223 - if(!vol->sz[2]) { 5.224 - fprintf(stderr, "file: %s contains no slices\n", fname); 5.225 - goto err; 5.226 - } 5.227 - 5.228 - return head; 5.229 - 5.230 -err: 5.231 - while(head) { 5.232 - struct slice *tmp = head; 5.233 - head = head->next; 5.234 - free(tmp->name); 5.235 - free(tmp); 5.236 - } 5.237 - if(fp) { 5.238 - fclose(fp); 5.239 - } 5.240 - return 0; 5.241 -} 5.242 - 5.243 -static char *trim(char *str) 5.244 -{ 5.245 - char *tmp = str + strlen(str) - 1; 5.246 - 5.247 - while(isspace(*tmp)) 5.248 - tmp--; 5.249 - tmp[1] = 0; 5.250 - 5.251 - tmp = str; 5.252 - while(isspace(*tmp)) 5.253 - tmp++; 5.254 - return tmp; 5.255 -}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/volume.cc Mon Apr 09 23:42:57 2012 +0300 6.3 @@ -0,0 +1,212 @@ 6.4 +#include <stdio.h> 6.5 +#include <stdlib.h> 6.6 +#include <string.h> 6.7 +#include <ctype.h> 6.8 +#include <list> 6.9 +#include <string> 6.10 + 6.11 +#ifndef __APPLE__ 6.12 +#include <GL/gl.h> 6.13 +#else 6.14 +#include <OpenGL/gl.h> 6.15 +#endif 6.16 + 6.17 +#include <imago2.h> 6.18 +#include "volume.h" 6.19 + 6.20 +static void calc_gradients(float *voxels, int xsz, int ysz, int zsz); 6.21 +static struct slice *read_voldesc(const char *fname, struct volume *vol); 6.22 +static char *trim(char *str); 6.23 + 6.24 +Volume::Volume() 6.25 +{ 6.26 + sz[0] = sz[1] = sz[2] = 0; 6.27 + zaspect = 1.0; 6.28 + tex = 0; 6.29 +} 6.30 + 6.31 +Volume::~Volume() 6.32 +{ 6.33 + if(tex) { 6.34 + glDeleteTextures(1, &tex); 6.35 + } 6.36 +} 6.37 + 6.38 +bool Volume::load(const char *fname) 6.39 +{ 6.40 + std::list<std::string> slist; 6.41 + float *voxels = 0, *vptr; 6.42 + struct img_pixmap img; 6.43 + 6.44 + if(!(read_voldesc(fname, &slist))) { 6.45 + return false; 6.46 + } 6.47 + 6.48 + /* load the first image to determine slice dimensions */ 6.49 + img_init(&img); 6.50 + if(img_load(&img, slist.begin().name.c_str()) == -1) { 6.51 + fprintf(stderr, "failed to load volume slice: %s\n", slist->name); 6.52 + return false; 6.53 + } 6.54 + 6.55 + sz[0] = img.width; 6.56 + sz[1] = img.height; 6.57 + printf("volume dimensions: %dx%dx%d\n", img.width, img.height, vol->sz[2]); 6.58 + 6.59 + /* allocate the whole volume at once */ 6.60 + voxels = new float[sz[0] * sz[1] * sz[2] * 4]; 6.61 + vptr = voxels; 6.62 + img_destroy(&img); 6.63 + 6.64 + /* put the volume data into the alpha component */ 6.65 + for(auto slice : slist) { 6.66 + int x, y, xsz, ysz; 6.67 + float *pixels, *src; 6.68 + 6.69 + if(!(pixels = img_load_pixels(slice.name.c_str(), &xsz, &ysz, IMG_FMT_GREYF))) { 6.70 + fprintf(stderr, "failed to load volume slice: %s\n", slice.name.c_str()); 6.71 + delete [] voxels; 6.72 + return false; 6.73 + } 6.74 + 6.75 + if(xsz != sz[0] || ysz != sz[1]) { 6.76 + fprintf(stderr, "inconsistent dimensions for slice %s: %dx%d (%dx%d expected)\n", 6.77 + slice.name.c_str(), xsz, ysz, sz[0], sz[1]); 6.78 + delete [] voxels; 6.79 + return false; 6.80 + } 6.81 + 6.82 + src = pixels; 6.83 + for(y=0; y<ysz; y++) { 6.84 + for(x=0; x<xsz; x++) { 6.85 + vptr[0] = vptr[1] = vptr[2] = 0.0f; 6.86 + vptr[3] = *src++; 6.87 + vptr += 4; 6.88 + } 6.89 + } 6.90 + img_free_pixels(pixels); 6.91 + } 6.92 + 6.93 + /* calculate gradients */ 6.94 + calc_gradients(voxels, sz[0], sz[1], sz[2]); 6.95 + 6.96 + /* create the volume texture */ 6.97 + glGenTextures(1, &tex); 6.98 + glBindTexture(GL_TEXTURE_3D, tex); 6.99 + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 6.100 + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 6.101 + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 6.102 + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 6.103 + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 6.104 + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F_ARB, sz[0], sz[1], sz[2], 0, GL_RGBA, GL_FLOAT, voxels); 6.105 + 6.106 + /* ... and destroy our copy */ 6.107 + delete [] voxels; 6.108 + return true; 6.109 +} 6.110 + 6.111 +unsigned int Volume::get_texture() const 6.112 +{ 6.113 + return tex; 6.114 +} 6.115 + 6.116 +void Volume::bind(int tex_unit) const 6.117 +{ 6.118 + glActiveTexture(GL_TEXTURE0 + tex_unit); 6.119 + glBindTexture(GL_TEXTURE_3D, tex); 6.120 +} 6.121 + 6.122 +struct vec4 { float x, y, z, w; }; 6.123 + 6.124 +static void calc_gradients(float *voxels, int xsz, int ysz, int zsz) 6.125 +{ 6.126 + int x, y, z, slice_pixels = xsz * ysz; 6.127 + vec4 *vptr = (vec4*)voxels; 6.128 + 6.129 + for(z=0; z<zsz; z++) { 6.130 + for(y=0; y<ysz; y++) { 6.131 + for(x=0; x<xsz; x++) { 6.132 + float x0, x1, y0, y1, z0, z1; 6.133 + 6.134 + x0 = x > 0 ? (vptr - 1)->w : vptr->w; 6.135 + y0 = y > 0 ? (vptr - xsz)->w : vptr->w; 6.136 + z0 = z > 0 ? (vptr - slice_pixels)->w : vptr->w; 6.137 + x1 = x < xsz - 1 ? (vptr + 1)->w : vptr->w; 6.138 + y1 = y < ysz - 1 ? (vptr + xsz)->w : vptr->w; 6.139 + z1 = z < zsz - 1 ? (vptr + slice_pixels)->w : vptr->w; 6.140 + 6.141 + vptr->x = x1 - x0; 6.142 + vptr->y = y1 - y0; 6.143 + vptr->z = z1 - z0; 6.144 + 6.145 + vptr++; 6.146 + } 6.147 + } 6.148 + } 6.149 +} 6.150 + 6.151 +bool read_voldesc(const char *fname, std::list<std::string> *slist) const 6.152 +{ 6.153 + FILE *fp = 0; 6.154 + char buf[512], *slash, *prefix = ""; 6.155 + int mode_slices = 0; 6.156 + 6.157 + slist->clear(); 6.158 + 6.159 + if(!(fp = fopen(fname, "r"))) { 6.160 + fprintf(stderr, "failed to open volume descriptor: %s\n", fname); 6.161 + return false; 6.162 + } 6.163 + fgets(buf, sizeof buf, fp); 6.164 + if(strstr(buf, "VOLDESC") != buf) { 6.165 + fprintf(stderr, "invalid file format while trying to read volume descriptor: %s\n", fname); 6.166 + fclose(fp); 6.167 + return false; 6.168 + } 6.169 + 6.170 + if((slash = strrchr(fname, '/'))) { 6.171 + int len = slash - fname + 1; 6.172 + prefix = alloca(len + 1); 6.173 + memcpy(prefix, fname, len); 6.174 + prefix[len] = 0; 6.175 + } 6.176 + 6.177 + while(fgets(buf, sizeof buf, fp)) { 6.178 + char *line = trim(buf); 6.179 + 6.180 + if(!*line || *line == '#') 6.181 + continue; 6.182 + 6.183 + if(mode_slices) { 6.184 + /* we're in the part that contains filenames... append to the list */ 6.185 + slist->push_back(std::string(prefix) + std::string(line)); 6.186 + sz[2]++; 6.187 + } else { 6.188 + /* TODO we're in the options part... parse */ 6.189 + if(strcmp(line, "SLICES") == 0) { 6.190 + mode_slices = 1; 6.191 + } 6.192 + } 6.193 + } 6.194 + fclose(fp); 6.195 + 6.196 + if(slist->empty()) { 6.197 + fprintf(stderr, "file: %s contains no slices\n", fname); 6.198 + return false; 6.199 + } 6.200 + return true; 6.201 +} 6.202 + 6.203 +static char *trim(char *str) 6.204 +{ 6.205 + char *tmp = str + strlen(str) - 1; 6.206 + 6.207 + while(isspace(*tmp)) 6.208 + tmp--; 6.209 + tmp[1] = 0; 6.210 + 6.211 + tmp = str; 6.212 + while(isspace(*tmp)) 6.213 + tmp++; 6.214 + return tmp; 6.215 +}
7.1 --- a/src/volume.h Sun Apr 08 14:31:03 2012 +0300 7.2 +++ b/src/volume.h Mon Apr 09 23:42:57 2012 +0300 7.3 @@ -1,15 +1,25 @@ 7.4 #ifndef VOLUME_H_ 7.5 #define VOLUME_H_ 7.6 7.7 -#include <stdint.h> 7.8 +#include <list> 7.9 +#include <string> 7.10 7.11 -struct volume { 7.12 +class Volume { 7.13 +private: 7.14 int sz[3]; 7.15 float zaspect; 7.16 - unsigned int tex_vol; 7.17 + unsigned int tex; 7.18 + 7.19 + bool read_voldesc(const char *fname, std::list<std::string> *slist) const; 7.20 + 7.21 +public: 7.22 + Volume(); 7.23 + ~Volume(); 7.24 + 7.25 + bool load(const char *fname); 7.26 + 7.27 + unsigned int get_texture() const; 7.28 + void bind(int tex_unit = 0) const; 7.29 }; 7.30 7.31 -struct volume *load_volume(const char *fname); 7.32 -void free_volume(struct volume *vol); 7.33 - 7.34 #endif /* VOLUME_H_ */