/* image.c */ /* * Vis5D system for visualizing five dimensional gridded data sets. * Copyright (C) 1990 - 2000 Bill Hibbard, Johan Kellum, Brian Paul, * Dave Santek, and Andre Battaiola. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * As a special exception to the terms of the GNU General Public * License, you are permitted to link Vis5D with (and distribute the * resulting source and executables) the LUI library (copyright by * Stellar Computer Inc. and licensed for distribution with Vis5D), * the McIDAS library, and/or the NetCDF library, where those * libraries are governed by the terms of their own licenses. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "../config.h" /* Texture/image mapping */ #include #include #include #include #include #include #ifdef HAVE_SGI_GL # include # include #endif #ifdef HAVE_OPENGL # include # include #endif #include "globals.h" #include "graphics.h" #include "rgb.h" #ifdef HAVE_SGI_GL /* * Lighting and texturing properties: */ static float mat2[] = { AMBIENT, 0.5, 0.5, 0.5, /* surface ambient color */ DIFFUSE, 0.9, 0.9, 0.9, /* surface diffuse color */ LMNULL }; static float lmodel2[] = { AMBIENT, 0.5, 0.5, 0.5, /* ambient color */ LOCALVIEWER, 0.0, /* infinite viewpoint */ TWOSIDE, 0, LMNULL }; static float texprops[] = { TX_MINFILTER, TX_POINT, TX_MAGFILTER, TX_POINT, TX_NULL }; static float tevprops[] = { TV_MODULATE, TV_NULL }; static float subdiv_params[] = { 0.0, 0.0, 10.0 }; #endif /* HAVE_SGI_GL */ #ifdef HAVE_MCIDAS /* * McIDAS stuff */ /* API - not to globals.c: only one call to init_mcidas_kludge for all Vis5D contexts */ int uc[1000]; int neguc[200]; int ttyfd[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; #define OPNARA F77_FUNC(opnara,OPNARA) #define READD F77_FUNC(readd,READD) #define RHELP F77_FUNC(rhelp,RHELP) #define CLSARA F77_FUNC(clsara,CLSARA) #define REDARA F77_FUNC(redara,REDARA) #define KLTWIN F77_FUNC(kltwin,KLTWIN) #define LWINIT F77_FUNC(lwinit,LWINIT) extern void OPNARA( int * ); extern void READD( int *, int * ); extern void RHELP( int *, int * ); extern void CLSARA( int * ); extern void REDARA( int *, int*, int *, int *, int *, void *); #ifndef MCIDAS_SIDECAR extern void KLTWIN( void ); extern void LWINIT( void ); static void init_mcidas_kludge( void ) /* API - call once for all contexts */ { int i; for (i=0; i<1000; i++) uc[i] = 0; for (i=0; i<200; i++) neguc[i] = 0; KLTWIN(); LWINIT(); } #endif /* end of ifndef MCIDAS_SIDECAR */ void F77_FUNC(zdest,ZDEST)( char *c, int *n, int len ) { int l; char s[100]; l = (len < 100) ? len : 99; strncpy(s, c, l); s[l] = 0; printf("%s %d\n", s, *n); } /* * Load a mcidas area and store it in packed ABGR format. * Input: area_num - number of mcidas area * Output: width, height - size of image read * data - pointer to image data * Return: 1 = ok, 0 = error. */ static int read_area( Display_Context dtx, int area_num, int *width, int *height, unsigned char **data ) { int idir[64], bytes, e, band; unsigned char data1[80000]; int x, y; int h, w; unsigned char *d; int ix; #ifdef NAV float dx, dy; int qr, qc, i, j, status; float x, y, z; float lat, lon, hgt; float xline, xelem, xdum, aline, aelem, lpct, epct; static float zero = 0.0; int line, elem, lres, eres; /* get area navigation */ if ((status = F77_FUNC(nvset,NVSET)("AREA ", &area_num, 12)) != 0) { if (status == -1) printf("no area %d\n", area_num); else if (status == -2) printf("gen_nav: no navigation for area %d\n", area_num); else printf("gen_nav: navigation problem for area %d %d\n", area_num, status); return 0; /* **** or just don't navigate area **** */ } #endif /*printf("area_num %d\n", area_num);*/ READD(&area_num, idir); if (idir[0] < 0) { /* unable to read area */ printf("Error: couldn't read AREA%04d, no areas read.\n",area_num); return 0; } OPNARA(&area_num); #ifdef NAV line = idir[5] + line * idir[11]; /* 5 - area line, 11 - area line res */ elem = idir[6] + elem * idir[12]; /* 6 - area elem, 12 - area elem res */ if (lres == 0) { printf("gen_nav: bad line res %d\n", lres); return 0; } else if (lres > 0) lres = idir[11] * lres; else lres = idir[11] / (-lres); if (eres == 0) { printf("gen_nav: bad elem res %d\n", eres); return 0; } else if (eres > 0) eres = idir[12] * eres; else eres = idir[12] / (-eres); #endif *height = h = idir[8]; /* if (h > 768) *height = h = 768; */ *width = w = idir[9]; bytes = idir[10]; d = (unsigned char *) malloc( w * h * sizeof(unsigned char)); *data = d; e = 0; band = (bytes == 1) ? 0 : 8; /*printf("h %d w %d bytes %d band %d\n", h, w, bytes, band);*/ /* new area stuff */ bytes = 1; RHELP(&area_num, &bytes); #ifdef NAV qr = dtx->qrows; qc = dtx->qcols; dx = (dtx->Xmax-dtx->Xmin) / (float) (qc-1); dy = (dtx->Ymax-dtx->Ymin) / (float) (qr-1); y = dtx->Ymax; for (i=0; iXmin; for (j=0; j=n */ if (m-n <= n-m/2) { return m; } else { return m/2; } } /**********************************************************************/ /**********************************************************************/ /***** Public Functions *****/ /**********************************************************************/ /**********************************************************************/ /* * Init global variables. */ void init_image( Display_Context dtx ) { int i; for (i=0;iNumTimes;i++) { dtx->TexWidth[i] = dtx->TexHeight[i] = 0; dtx->TexComponents[i] = 0; free(dtx->TexImage[i]); dtx->TexImage[i] = NULL; dtx->TexImageNew[i] = 1; } } /* * Define the texture to be used for the given timestep. The image data * is not copied; just the pointer to it is saved. */ void define_texture( Display_Context dtx, int time, int width, int height, int components, void *image ) { assert( time>=0 && time<=dtx->NumTimes ); dtx->TexWidth[time] = width; dtx->TexHeight[time] = height; dtx->TexComponents[time] = components; if (dtx->TexImage[time]){ free(dtx->TexImage[time]); } dtx->TexImage[time] = image; } /* * Read a texture map from the named file. The image can be any SGI * .rgb file. * Input: filename - name of image file * Return: 1 = ok, 0 = error. */ int read_texture_image( Display_Context dtx, char *filename ) { RGB_IMAGE *img; int width, height; int i; unsigned int *image; img = ReadRGB( filename ); if (!img) return 0; width = img->sizeX; height = img->sizeY; if (width>1024) { /* too wide */ FreeRGB( img ); return 0; } image = (unsigned int *) img->data; #ifdef HAVE_OPENGL /* The texture size *MUST* be a power of two. Rescale now if needed. */ { int width2, height2, max; width2 = round2( width ); height2 = round2( height ); glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max ); if (width2>max) width2 = max; if (height2>max) height2 = max; if (width!=width2 || height!=height2) { unsigned int *image2; image2 = (unsigned int *) malloc( width2 * height2 * 4 ); gluScaleImage( GL_RGBA, width, height, GL_UNSIGNED_BYTE, image, width2, height2, GL_UNSIGNED_BYTE, image2 ); width = width2; height = height2; image = image2; } check_gl_error( "read_texture_image" ); } #endif /*ifdef HAVE_OPENGL*/ /* use same texture for all timesteps */ for (i=0;iNumTimes;i++) { define_texture( dtx, i, width, height, 4, image ); } /* FreeRGB(img);*/ return 1; } /* WLH 11-25-94 * Read a sequence of images from a file, to use for texture mapping. * Input: name - name of file. * Return: 1 = ok, 0 = error. */ int read_texture_sequence( Display_Context dtx, char *name ) { int i, length, fd, head[3]; int width, height, max; unsigned char *data; if ((fd = open(name, O_RDONLY, 0)) == -1) { return 0; /* cannot open file */ } length = 3 * sizeof(int); if (read(fd, head, length) != length) { return 0; /* cannot read file header */ } if (head[0] < dtx->NumTimes) { return 0; /* not enough time steps in file */ } for (i=0;iNumTimes;i++) { height = head[1]; width = head[2]; length = width * height * sizeof(unsigned char); data = (unsigned char *) malloc(length); if (read(fd, data, length) != length) { return 0; /* cannot read image from file */ } #ifdef HAVE_OPENGL /* The texture size *MUST* be a power of two. Rescale now if needed. */ { int width2, height2; unsigned char *data2; width2 = round2( width ); height2 = round2( height ); glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max ); if (width2>max) width2 = max; if (height2>max) height2 = max; if (width!=width2 || height!=height2) { data2 = (unsigned char *) malloc( width2 * height2 ); gluScaleImage( GL_LUMINANCE, width, height, GL_UNSIGNED_BYTE, data, width2, height2, GL_UNSIGNED_BYTE, data2 ); free( data ); width = width2; height = height2; data = data2; } check_gl_error( "read_texture_sequence" ); } #endif define_texture( dtx, i, width, height, 1, data ); } return 1; } #ifdef HAVE_MCIDAS /* * Read a sequence of McIDAS area files to use for texture mapping. * Input: first - number of first AREA file in the sequence. * Return: 1 = ok, 0 = error. */ int read_texture_areas( Display_Context dtx, int first ) { int i; int width, height; unsigned int *image; #ifndef MCIDAS_SIDECAR init_mcidas_kludge(); #endif for (i=0;iNumTimes;i++) { if (!read_area( dtx, first+i, &width, &height, (unsigned char **) &image )) { /* error */ return 0; } #ifdef HAVE_OPENGL /* The texture size *MUST* be a power of two. Rescale now if needed. */ { int width2, height2, max; unsigned int *image2; width2 = round2( width ); height2 = round2( height ); glGetIntegerv( GL_MAX_TEXTURE_SIZE, &max ); if (width2>max) width2 = max; if (height2>max) height2 = max; if (width!=width2 || height!=height2) { unsigned int *image2; image2 = (unsigned int *) malloc( width2 * height2 * 4 ); gluScaleImage( GL_LUMINANCE, width, height, GL_UNSIGNED_BYTE, image, width2, height2, GL_UNSIGNED_BYTE, image2 ); free( image ); width = width2; height = height2; image = image2; } check_gl_error( "read_texture_areas" ); } #endif define_texture( dtx, i, width, height, 1, image ); } return 1; } #endif /* ifdef HAVE_MCIDAS */ /* * Specify which texture to use. If time==-1, disable texturing. */ int use_texture( Display_Context dtx, int time ) { assert( time>=0 && timeNumTimes ); /* Do one-time initializations */ if (dtx->init_flag) { #ifdef HAVE_SGI_GL /* define special material and lighting model for texturing */ lmdef( DEFMATERIAL, 11, 0, mat2 ); lmdef( DEFLMODEL, 31, 0, lmodel2 ); #endif #ifdef HAVE_OPENGL glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); check_gl_error( "use_texture (glTexParameter)" ); #endif dtx->init_flag = 0; } /* Give the texture to the graphics library / hardware */ if (dtx->TexImage[time]) { if (dtx->prev_time==-1 || dtx->TexImage[dtx->prev_time]!=dtx->TexImage[time] || dtx->TexImageNew[time] == 1) { #ifdef HAVE_SGI_GL texdef2d( 1, dtx->TexComponents[time], dtx->TexWidth[time], dtx->TexHeight[time], (unsigned long *) dtx->TexImage[time], 5, texprops ); tevdef( 1, 0, tevprops ); #endif #ifdef HAVE_OPENGL if (dtx->TexComponents[time]==1) { glTexImage2D( GL_TEXTURE_2D, 0, 1, dtx->TexWidth[time], dtx->TexHeight[time], 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, dtx->TexImage[time] ); } else { glTexImage2D( GL_TEXTURE_2D, 0, dtx->TexComponents[time], dtx->TexWidth[time], dtx->TexHeight[time], 0, GL_RGBA, GL_UNSIGNED_BYTE, dtx->TexImage[time] ); } check_gl_error( "use_texture (glTexImage2D)" ); #endif dtx->TexImageNew[time] = 0; } } dtx->prev_time = time; return 0; } /* * Enable or disable texture mapping. */ static void enable_texture( int enable ) { if (enable) { #ifdef HAVE_SGI_GL texbind( TX_TEXTURE_0, 1 ); tevbind( TV_ENV0, 1 ); scrsubdivide( SS_DEPTH, subdiv_params ); /* special lighting parameters */ lmbind( MATERIAL, 11 ); lmbind( LMODEL, 31 ); /*lmcolor( LMC_AD ); Added on 4-11-95 by BEP */ cpack( 0xffffffff ); #endif #ifdef HAVE_OPENGL glEnable( GL_TEXTURE_2D ); glEnable( GL_LIGHTING ); glColor4f( 1.0, 1.0, 1.0, 1.0 ); check_gl_error( "enable_texture (glEnable)" ); #endif } else { /* disable */ #ifdef HAVE_SGI_GL texbind( TX_TEXTURE_0, 0 ); tevbind( TV_ENV0, 0 ); scrsubdivide( SS_OFF, subdiv_params ); /* regular lighting */ lmbind( MATERIAL, 10 ); lmbind( LMODEL, 30 ); #endif #ifdef HAVE_OPENGL glDisable( GL_TEXTURE_2D ); glDisable( GL_LIGHTING ); check_gl_error( "enable_texture (glDisable)" ); #endif } } /* * Draw a texture mapped quadrilateral mesh using the currently defined * texture. */ int texture_quadmeshnorm( int rows, int cols, float vert[][3], float norm[][3], float texcoord[][2] ) { int i, j, base1, base2; /* turn on texture mapping */ enable_texture(1); /* break mesh into strips */ for (i=0;i