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_ */