Original Post
Hi! I have a problem with the code below. It loads a model in rvf format and render it using 2D textures. The problem is that when I use modify the opacity of the color palette, the model disappears and I can't find why. Note that I am running it on Linux RHEL 3.0 with ATI9200 graphics card (direct rendering enabled). I can send the project by email if necessary. Many thanks.
/*
* file : volume.c
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <GL/glut.h>
#include "texture3d.h"
#include "tga.h"
#include "bmp.h"
/* display list */
#define Z_FRONT 1
#define Z_BACK 2
#define Y_FRONT 3
#define Y_BACK 4
#define X_FRONT 5
#define X_BACK 6
/* palette */
#define PALETTE_SIZE 32
#define PALETTE_XOFFSET 5
#define PALETTE_YOFFSET 5
/* mouse mode */
#define ROTATION 1
#define COLOR_SELECTION 2
/* globals */
int xs=500,ys=400;
/* BLEND and DEPTH_TEST */
int alpha=1,depth=0;
int drawCube=1,projection=1;
int s1,s2,s3;
/* rotation & mouse */
float scaleFactor=1.;
int oldx=0,oldy=0,xrot=0,yrot=0;
int dx,dy;
int inverseZ=1;
int mode=ROTATION;
int color_1,color_2;
/* texture */
tex3 tex;
int px,py,pz;
GLuint *XTextureId;
GLuint *YTextureId;
GLuint *ZTextureId;
unsigned char *tex_buf;
/* palette */
char *palname="default.pal";
GLuint checkerId;
unsigned char *pal;
unsigned char *reset_pal;
//char *filename="vht.rvf";
char *filename="brainsmall.rvf";
//char *filename="teddybear.raw"; // 128*128*62
//char *filename="head.raw";
//char *filename="engine.raw";
//char* filename="nucleon.raw";
//char *filename="CT_Head_small.raw";
/* profiling */
int frame=0;
int oldtime=0;
int power[10]={
1,2,4,8,16,32,64,128,256,512};
/* find the nearest power of two after t */
int nextPower(int t){
int i;
for(i=0;i<10;i++){
if (power>=t)
return power;
}
return 512;
}
/* load a nice default palette */
void load_default_palette(unsigned char *pal){
int i;
for(i=0;i<85;i++){
pal[4*i+0]=i*3;
pal[4*i+1]=0;
pal[4*i+2]=0;
pal[4*i+3]=i;
}
for(i=0;i<85;i++){
pal[4*(i+85)+0]=255;
pal[4*(i+85)+1]=i*3;
pal[4*(i+85)+2]=0;
pal[4*(i+85)+3]=i+85;
}
for(i=0;i<86;i++){
pal[4*(i+85+85)+0]=(85-i)*3;
pal[4*(i+85+85)+1]=255;
pal[4*(i+85+85)+2]=i*3;
pal[4*(i+85+85)+3]=i+85+85;
}
}
/* load a palette from an ASCII file (unix's return style )*/
int load_palette(char *name,unsigned char *c){
FILE *fp;
int index=0;
fp=fopen(name,"r");
if (fp==NULL)
return -1;
while(fscanf(fp,"%d %d %d %d",c+index*4+0,c+index*4+1,c+index*4+2,c+index*4+3)==4){
// glutSetColor(index,(float)c[index*4]/256.,(float)c[index*4+1]/256.,(float)c[index*4+2]/256.);
index++;
}
fclose(fp);
return index!=256;
}
/* make the palette from c1 to c2 transparent */
void zeroAlpha(unsigned char *c,int c1,int c2){
int i;
if (c1>c2){
i=c1;
c1=c2;
c2=i;
}
for(i=c1;i<=c2;i++){
c[i*4+3]=0;
}
}
/* reset the palette from c1 to c2 */
void resetAlpha(unsigned char *c,int c1,int c2){
int i;
if (c1>c2){
i=c1;
c1=c2;
c2=i;
}
for(i=c1;i<=c2;i++){
c[i*4+3]=reset_pal[i*4+3];
}
}
void init_palette(){
/* try to load the palette */
pal=(unsigned char*)malloc(256*4);
if (pal==NULL){
fprintf(stderr,"Out of memory\n");
exit(-1);
}
reset_pal=(unsigned char *)malloc(4*256);
if (reset_pal==NULL){
fprintf(stderr,"load_default_palette() : Out of memory\n");
exit(-1);
}
if (load_palette(palname,reset_pal)){
printf("no palette found (making default)\n");
load_default_palette(reset_pal);
}
/* copy it */
memcpy(pal,reset_pal,4*256);
// test opacity
zeroAlpha(pal,0,20);
zeroAlpha(pal,240,255);
}
/* load a volume and create slices of it */
void load_tex(char *name){
unsigned char *checker_buf;
int i,j,k;
float x,y,z;
init_palette();
/* load it */
printf("loading 3d texture '%s' ... ",name);
fflush(stdout);
// if (load_raw(&tex,name,128,128,62)){
if (load_rvf(&tex,name)){
fprintf(stderr,"abort\n");
exit(-1);
}
px=nextPower(tex.x);
py=nextPower(tex.y);
pz=nextPower(tex.z);
printf("done (%dx%dx%d)->(%dx%dx%d)\n",tex.x,tex.y,tex.z,px,py,pz);
/* ask for some textures */
XTextureId=(GLuint *)malloc(sizeof(GLuint)*tex.x);
if (XTextureId==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
YTextureId=(GLuint *)malloc(sizeof(GLuint)*tex.y);
if (YTextureId==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
ZTextureId=(GLuint *)malloc(sizeof(GLuint)*tex.z);
if (ZTextureId==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
/* generate textures */
glGenTextures(tex.x,XTextureId);
glGenTextures(tex.y,YTextureId);
glGenTextures(tex.z,ZTextureId);
glGenTextures(1,&checkerId);
/* create slices */
printf("creating slices [");
fflush(stdout);
/* xy slices */
/* allocate a texture buffer */
tex_buf=(unsigned char *)calloc(4*px*py,1);
if (tex_buf==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
/* xy-->z */
for (k=0;k<tex.z;k+=1){
if (floor(10.*k/tex.z)==(10.*k/tex.z)){
printf("#");
fflush(stdout);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D,ZTextureId[k]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
for(i=0;i<tex.x;i++){
for(j=0;j<tex.y;j++){
tex_buf[(i+j*px)*4+0]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+0];
tex_buf[(i+j*px)*4+1]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+1];
tex_buf[(i+j*px)*4+2]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+2];
tex_buf[(i+j*px)*4+3]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+3];
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, px,py,0,GL_RGBA,GL_UNSIGNED_BYTE,tex_buf);
}
free(tex_buf);
printf("|");
fflush(stdout);
/* yz slices */
/* allocate a new texture buffer */
tex_buf=(unsigned char *)calloc(4*pz*py,1);
memset(tex_buf,0,4*pz*py);
if (tex_buf==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
/* zy-->x */
for (i=0;i<tex.x;i+=1){
if (floor(10.*i/tex.x)==(10.*i/tex.x)){
printf("#");
fflush(stdout);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D,XTextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
for(k=0;k<tex.z;k++){
for(j=0;j<tex.y;j++){
tex_buf[(k+j*pz)*4+0]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+0];
tex_buf[(k+j*pz)*4+1]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+1];
tex_buf[(k+j*pz)*4+2]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+2];
tex_buf[(k+j*pz)*4+3]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+3];
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pz,py,0,GL_RGBA,GL_UNSIGNED_BYTE,tex_buf);
}
free(tex_buf);
printf("|");
fflush(stdout);
/* xz slices */
/* allocate a new texture buffer */
tex_buf=(unsigned char *)calloc(4*pz*px,1);
if (tex_buf==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
/* xz-->y */
for (j=0;j<tex.y;j+=1){
if (floor(10.*j/tex.y)==(10.*j/tex.y)){
printf("#");
fflush(stdout);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D,YTextureId[j]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
for(k=0;k<tex.z;k++){
for(i=0;i<tex.x;i++){
tex_buf[(i+k*px)*4+0]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+0];
tex_buf[(i+k*px)*4+1]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+1];
tex_buf[(i+k*px)*4+2]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+2];
tex_buf[(i+k*px)*4+3]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+3];
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, px,pz,0,GL_RGBA,GL_UNSIGNED_BYTE,tex_buf);
}
free(tex_buf);
printf("] done\n");
fflush(stdout);
/* a nice checker texture for the palette's background */
checker_buf=(unsigned char *)malloc(4*PALETTE_SIZE*256);
if (checker_buf==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D,checkerId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
for(i=0;i<PALETTE_SIZE;i++){
for(j=0;j<256;j++){
int a,b,c,step;
step=8;
a=!((i/step)%2*255);
b=((j/step)%2*255);
c=a?(b?255:0):
(b?0:255);
checker_buf[(i+j*PALETTE_SIZE)*4+0]=c;
checker_buf[(i+j*PALETTE_SIZE)*4+1]=c;
checker_buf[(i+j*PALETTE_SIZE)*4+2]=c;
checker_buf[(i+j*PALETTE_SIZE)*4+3]=(!c)*255;
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,PALETTE_SIZE,256,0,GL_RGBA,GL_UNSIGNED_BYTE,checker_buf);
free(checker_buf);
/* display lists */
printf("making the display list ... ");
fflush(stdout);
/* We must draw slices from back to front in order to have a correct blending.
* That's why we have to create a list for each case
*/
glNewList(Z_FRONT,GL_COMPILE);
for(k=pz-tex.z;k<pz;k++){
z=1.-2.*k/pz;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,ZTextureId[pz-k-1]);
glBegin(GL_QUADS);
glTexCoord2f(0,1);
glVertex3f(-1,1,z);
glTexCoord2f(1,1);
glVertex3f(1,1,z);
glTexCoord2f(1,0);
glVertex3f(1,-1,z);
glTexCoord2f(0,0);
glVertex3f(-1,-1,z);
glEnd();
}
glEndList();
glNewList(Z_BACK,GL_COMPILE);
for(k=pz;k>(pz-tex.z);k--){
z=1.-2.*k/pz;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,ZTextureId[pz-k]);
glBegin(GL_QUADS);
glTexCoord2f(0,1);
glVertex3f(-1,1,z);
glTexCoord2f(1,1);
glVertex3f(1,1,z);
glTexCoord2f(1,0);
glVertex3f(1,-1,z);
glTexCoord2f(0,0);
glVertex3f(-1,-1,z);
glEnd();
}
glEndList();
glNewList(X_FRONT,GL_COMPILE);
for(i=px;i>(px-tex.x);i--){
x=-1.+2.*i/px;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,XTextureId[tex.x-px+i-1]);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(x,-1,-1);
glTexCoord2f(0,1);
glVertex3f(x,1,-1);
glTexCoord2f(1,1);
glVertex3f(x,1,1);
glTexCoord2f(1,0);
glVertex3f(x,-1,1);
glEnd();
}
glEndList();
glNewList(X_BACK,GL_COMPILE);
for(i=px;i>(px-tex.x);i--){
x=1.-2.*i/px;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,XTextureId[px-i]);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(x,-1,-1);
glTexCoord2f(0,1);
glVertex3f(x,1,-1);
glTexCoord2f(1,1);
glVertex3f(x,1,1);
glTexCoord2f(1,0);
glVertex3f(x,-1,1);
glEnd();
}
glEndList();
glNewList(Y_FRONT,GL_COMPILE);
for(j=py;j>(py-tex.y);j--){
y=-1.+2.*j/py;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,YTextureId[tex.y-py+j-1]);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(-1,y,-1);
glTexCoord2f(0,1);
glVertex3f(-1,y,1);
glTexCoord2f(1,1);
glVertex3f(1,y,1);
glTexCoord2f(1,0);
glVertex3f(1,y,-1);
glEnd();
}
glEndList();
glNewList(Y_BACK,GL_COMPILE);
for(j=py;j>(py-tex.y);j--){
y=1.-2.*j/py;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,YTextureId[py-j]);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(-1,y,-1);
glTexCoord2f(0,1);
glVertex3f(-1,y,1);
glTexCoord2f(1,1);
glVertex3f(1,y,1);
glTexCoord2f(1,0);
glVertex3f(1,y,-1);
glEnd();
}
glEndList();
printf("done\n");
}
/* my nvidia tnt2 doesn't have the paletted texture extension */
void update_tex(){
int i,j,k;
// float x,y,z;
/* delete old textures */
printf("updating 3d texture ... [");
fflush(stdout);
glDeleteTextures(tex.x,XTextureId);
glDeleteTextures(tex.y,YTextureId);
glDeleteTextures(tex.z,ZTextureId);
if (XTextureId==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
if (YTextureId==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
if (ZTextureId==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
/* generate textures */
glGenTextures(tex.x,XTextureId);
glGenTextures(tex.y,YTextureId);
glGenTextures(tex.z,ZTextureId);
// xy-->z
tex_buf=(unsigned char *)calloc(4*px*py,1);
memset(tex_buf,0,4*px*py);
if (tex_buf==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
for (k=0;k<tex.z;k+=1){
if (floor(10.*k/tex.z)==10.*k/tex.z){
printf("#");
fflush(stdout);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D,ZTextureId[k]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
for(i=0;i<tex.x;i++){
for(j=0;j<tex.y;j++){
tex_buf[(i+j*px)*4+0]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+0];
tex_buf[(i+j*px)*4+1]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+1];
tex_buf[(i+j*px)*4+2]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+2];
tex_buf[(i+j*px)*4+3]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+3];
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, px,py,0,GL_RGBA,GL_UNSIGNED_BYTE,tex_buf);
}
free(tex_buf);
// zy-->x
tex_buf=(unsigned char *)calloc(4*pz*py,1);
memset(tex_buf,0,4*pz*py);
if (tex_buf==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
for (i=0;i<tex.x;i+=1){
if (floor(10.*i/tex.x)==10.*i/tex.x){
printf("#");
fflush(stdout);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D,XTextureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
for(k=0;k<tex.z;k++){
for(j=0;j<tex.y;j++){
tex_buf[(k+j*pz)*4+0]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+0];
tex_buf[(k+j*pz)*4+1]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+1];
tex_buf[(k+j*pz)*4+2]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+2];
tex_buf[(k+j*pz)*4+3]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+3];
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pz,py,0,GL_RGBA,GL_UNSIGNED_BYTE,tex_buf);
}
free(tex_buf);
tex_buf=(unsigned char *)calloc(4*pz*px,1);
memset(tex_buf,0,4*pz*px);
if (tex_buf==NULL){
fprintf(stderr,"load_tex() : Out of memory\n");
exit(-1);
}
// xz-->y
for (j=0;
j<tex.y;
j+=1){
if (floor(10.*j/tex.y)==10.*j/tex.y){
printf("#");
fflush(stdout);
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D,YTextureId[j]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR);
for(k=0;k<tex.z;k++){
for(i=0;i<tex.x;i++){
tex_buf[(i+k*px)*4+0]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+0];
tex_buf[(i+k*px)*4+1]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+1];
tex_buf[(i+k*px)*4+2]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+2];
tex_buf[(i+k*px)*4+3]=pal[tex.texture[i+tex.x*(j+tex.y*k)]*4+3];
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, px,pz,0,GL_RGBA,GL_UNSIGNED_BYTE,tex_buf);
}
free(tex_buf);
printf("] done\n");
}
/* draw the palette */
void drawPalette(unsigned char *pal){
int i;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,xs,0,ys,0.001,1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(0.5,0.5,0.5);
/* background */
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,checkerId);
glBegin(GL_QUADS);
glTexCoord2f(0,1);
glVertex3f(xs-PALETTE_SIZE-PALETTE_XOFFSET,PALETTE_YOFFSET,-1);
glTexCoord2f(1,1);
glVertex3f(xs-PALETTE_XOFFSET,PALETTE_YOFFSET,-1);
glTexCoord2f(1,0);
glVertex3f(xs-PALETTE_XOFFSET,256+PALETTE_YOFFSET,-1);
glTexCoord2f(0,0);
glVertex3f(xs-PALETTE_SIZE-PALETTE_XOFFSET,256+PALETTE_YOFFSET,-1);
glEnd();
glDisable(GL_TEXTURE_2D);
/* palette */
for(i=0;i<256;i++){
glColor4ub(pal[i*4+0],pal[i*4+1],pal[i*4+2],pal[i*4+3]);
glBegin(GL_LINES);
glVertex3f(xs-PALETTE_SIZE-PALETTE_XOFFSET,i+PALETTE_YOFFSET,-1);
glVertex3f(xs-PALETTE_XOFFSET,i+PALETTE_YOFFSET,-1);
glEnd();
}
glColor3f(0,0,0);
glBegin(GL_LINE_LOOP);
glVertex3f(xs-PALETTE_SIZE-PALETTE_XOFFSET-3,PALETTE_YOFFSET-3,-1);
glVertex3f(xs-PALETTE_XOFFSET+3,PALETTE_YOFFSET-3,-1);
glVertex3f(xs-PALETTE_XOFFSET+3,256+PALETTE_YOFFSET+3,-1);
glVertex3f(xs-PALETTE_SIZE-PALETTE_XOFFSET-3,256+PALETTE_YOFFSET+3,-1);
glEnd();
/* selection */
if (mode==COLOR_SELECTION){
glColor3f(0,0,0);
glBegin(GL_LINE_LOOP);
glVertex3f(xs-PALETTE_SIZE-PALETTE_XOFFSET,color_1+PALETTE_YOFFSET,-1);
glVertex3f(xs-PALETTE_XOFFSET,color_1+PALETTE_YOFFSET,-1);
glVertex3f(xs-PALETTE_XOFFSET,color_2+PALETTE_YOFFSET,-1);
glVertex3f(xs-PALETTE_SIZE-PALETTE_XOFFSET,color_2+PALETTE_YOFFSET,-1);
glEnd();
}
}
void draw(){
// float z;
// int k;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (projection)
gluPerspective(40.,(float)(xs-PALETTE_SIZE)/(float)ys,0.1,1000);
else
glOrtho(-2,2,-2,2,0,1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,2,-5,0,0,0,0,1,0);
glRotatef(yrot,-1,0,0);
glRotatef(xrot,0,1,0);
glScalef(scaleFactor,(inverseZ?-1:1)*scaleFactor,scaleFactor);
glEnable(GL_TEXTURE_2D);
glColor3f(1,1,1);
/* select which set of slices we should draw */
if (yrot>23&&yrot<(23+90)){
glCallList(Y_FRONT);
}
else{
if (yrot<293&&yrot>(293-90)){
glCallList(Y_BACK);
}
else{
if (xrot>=315||xrot<=45){
glCallList(Z_FRONT);
}
else {
if (xrot>=135&&xrot<=225){
glCallList(Z_BACK);
}
else{
if (xrot>=45&&xrot<=135){
glCallList(X_BACK);
}
else {
glCallList(X_FRONT);
}
}
}
}
}
/* cube */
if (drawCube){
glDisable(GL_TEXTURE_2D);
glColor3f(0,0,0);
glLineWidth(1.5);
glutWireCube(2);
}
/* palette */
drawPalette(pal);
glutSwapBuffers();
frame++;
}
void reshape(int w, int h){
xs=w;
ys=h;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (projection)
gluPerspective(40.,(float)(w-PALETTE_SIZE)/(float)h,0.1,1000);
else
glOrtho(-2,2,-2,2,0,1000);
glEnable(GL_TEXTURE_2D);
}
void mouse(int b,int state,int x,int y){
if(state == GLUT_DOWN) {
color_1=ys-y-PALETTE_YOFFSET;
if (x>(xs-PALETTE_SIZE-PALETTE_XOFFSET)&&x<(xs-PALETTE_XOFFSET)){
if (color_1>=0&&color_1<256){
mode=COLOR_SELECTION;
color_2=color_1;
return;
}
}
mode=ROTATION;
oldx = x;
oldy = y;
}
if (state==GLUT_UP){
if (mode==COLOR_SELECTION){
color_2=ys-y-PALETTE_YOFFSET;
if (color_2<0)
color_2=0;
else
if (color_2>255)
color_2=255;
/* make the selection transparent */
if (b==GLUT_LEFT_BUTTON)
zeroAlpha(pal,color_1,color_2);
if (b==GLUT_RIGHT_BUTTON)
resetAlpha(pal,color_1,color_2);
mode=ROTATION;
update_tex();
}
}
draw();
}
void motion(int x, int y) {
if (mode==ROTATION){
dx = x - oldx;
dy = y - oldy;
oldx = x;
oldy = y;
xrot+=dx/2;
yrot+=dy/2;
xrot=xrot<0?(xrot%360)+360:xrot%360;
yrot=yrot<0?(yrot%360)+360:yrot%360;
}
if (mode==COLOR_SELECTION){
color_2=ys-y-PALETTE_YOFFSET;
if (color_2<0)
color_2=0;
else
if (color_2>255)
color_2=255;
}
draw();
}
void idle(){
char title[256];
if (clock()-oldtime>CLOCKS_PER_SEC){
sprintf(title,"Volume rendering with gl (%dfps)",frame);
glutSetWindowTitle(title);
frame=0;
oldtime=clock();
}
// draw();
}
void keyboard(unsigned char key, int x, int y){
// tga_t tga;
bmp_t bmp;
unsigned char *buf;
char fn[256];
static int id=0;
switch (key) {
case 'h':
printf(" [s] - take a snapshot \n");
printf(" [+|-] - zoom \n");
printf(" [c] - toggle axis \n");
printf(" - toggle projection mode\n");
printf(" [z] - inverse z axis\n");
printf(" [r] - reset palette\n");
break;
case 's':
init_bmp(&bmp,xs,ys,24);
buf=(unsigned char*)malloc(3*xs*ys);
if (buf==NULL){
fprintf(stderr,"Out of memory\n");
return;
}
glReadPixels(0, 0,xs,ys,GL_RGB,GL_UNSIGNED_BYTE, buf);
sprintf(fn,"%s.%02d.bmp",filename,id);
save_bmp(bmp,buf,fn);
free(buf);
id++;
break;
case '+':
scaleFactor+=0.2;
glutPostRedisplay();
break;
case '-':
scaleFactor-=0.2;
glutPostRedisplay();
break;
case 'a':
if (alpha=!alpha)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
glutPostRedisplay();
printf("alpha [%s]\n",alpha?"on":"off");
break;
case 'd':
if (depth=!depth)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
glutPostRedisplay();
printf("depth [%s]\n",depth?"on":"off");
break;
case 'c':
printf("cube [%s]\n",(drawCube=!drawCube)?"on":"off");
glutPostRedisplay();
break;
case 'p':
printf("projection [%s]\n",(projection=!projection)?"perspective":"orthogonal");
reshape(xs,ys);
glutPostRedisplay();
break;
case 'z':
printf("z [%s]\n",(inverseZ=!inverseZ)?"on":"off");
glutPostRedisplay();
break;
case 'r':
printf("reset palette\n");
memcpy(pal,reset_pal,256*4);
update_tex();
break;
case 27:
if (tex.texture)
free(tex.texture);
exit(0);
break;
}
}
int main(int argc, char** argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
/* glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);*/
glutInitWindowSize (xs,ys);
glutInitWindowPosition (0,0);
glutCreateWindow("Volume rendering with gl");
glutReshapeFunc(reshape);
glutDisplayFunc(draw);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutKeyboardFunc (keyboard);
glutIdleFunc(idle);
/* enable transparency */
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
/* disable depth test */
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
/* check if there is an argument */
filename=argc>1?argv[1]:filename;
/* load the volume */
load_tex(filename);
/* I like this color */
glClearColor(1,1,1,1);
glutMainLoop();
return 0;
}