/* * Copyright (C) 2001-2003, R3vis Corporation. * * 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. * * 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, * or visit http://www.gnu.org/copyleft/gpl.html. * * Contributor(s): * Wes Bethel, R3vis Corporation, Marin County, California * * The OpenRM project is located at http://openrm.sourceforge.net/. */ /* * $Id: dyntmap.c,v 1.5 2003/04/13 18:13:23 wes Exp $ * $Revision: 1.5 $ * $Name: OpenRM-1-5-2-RC1 $ * $Log: dyntmap.c,v $ * Revision 1.5 2003/04/13 18:13:23 wes * Updated copyright dates. * * Revision 1.4 2003/01/27 05:07:07 wes * Changes to RMpipe initialization sequence APIs. Tested for GLX, but not WGL. * * Revision 1.3 2003/01/16 22:22:45 wes * Updated all source files to reflect new organization of header files: all * headers that were formerly located in include/rmaux, include/rmv and * include/rmi are now located in include/rm. * * Revision 1.2 2002/06/17 00:35:11 wes * Final 1.4.2 checkin. * * Revision 1.1 2002/04/30 19:43:30 wes * Initial entry. * */ /* */ #include <stdio.h> #ifndef RM_WIN #include <unistd.h> #endif #include <rm/rm.h> #include <rm/rmaux.h> #include "procmode.h" static RMpipe *myPipe=NULL; #define DEFAULT_IMAGE_WIDTH 640 #define DEFAULT_IMAGE_HEIGHT 525 /* * the "raw data file" is just raw byte information. a priori knowledge * about the size is required in order to use this program. the size of * the volume is compiled into this program. */ #define RAW_WIDTH 256 #define RAW_HEIGHT 64 #define RAW_DEPTH 256 char datafilename[256]={"data/volume.dat"}; typedef unsigned char dataptr; dataptr *rawVolumeData=NULL; RMvisMap *vmap = NULL; RMnode *textureNode=NULL; static int frameCounter = 0; static int do_color = 0; void readData(char *datafilename) { FILE *f; RMimage *src_volume; int npts=RAW_WIDTH*RAW_DEPTH*RAW_HEIGHT; int final_width, final_height, final_depth; vmap = rmDefaultVismap(); /* creates a hue ramp */ rmVismapSetTfMin(vmap,0.0F); rmVismapSetTfMax(vmap,255.0F); if (do_color == 0) { /* * rebuild the colormap/transfer function so that it's a * gray ramp. this looks better than just using GL_ALPHA * as the image data format. * * Ramp from 0..1 (gray) between indices 0..127. Then, ramp back * down from 1 to 0 from 127..255. * */ int i; RMcolor4D c={0.F,0.F,0.F,0.F}; double dc; dc = 1./127.; for (i=0;i<127;i++) { rmVismapSetColor4D(vmap,i,&c); c.r += dc; c.g += dc; c.b += dc; c.a += dc; } for (i=i;i<256;i++) { rmVismapSetColor4D(vmap,i,&c); c.r -= dc; c.g -= dc; c.b -= dc; c.a -= dc; } } printf(" loading raw volume data..."); rawVolumeData = (unsigned char *)malloc(sizeof(unsigned char)*npts); f = fopen(datafilename,"r"); fread((void *)rawVolumeData,sizeof(unsigned char),npts,f); fclose(f); printf("done \n"); } void setTexture(RMnode *n, /* the RMnode containing an RMtexture */ int z, /* which z-slice of data to load */ int frameCounter) /* which frame */ { /* * this routine will read in the next slice of volume data, create an * RMimage from the data, and update the RMtexture at the RMnode n. * The RMtexture is created only on the first execution. Otherwise, * the RMtexture is obtained by querying the RMnode, and updating * the RMtexture's RMimage texture data. */ dataptr *p; RMimage *i = rmImageNew(2, RAW_WIDTH, RAW_HEIGHT, 1, RM_IMAGE_LUMINANCE, RM_UNSIGNED_BYTE, RM_COPY_DATA); int initialOffset = RAW_WIDTH * RAW_HEIGHT * z; p = rawVolumeData + initialOffset; rmImageSetPixelData(i, p, RM_COPY_DATA, NULL); rmImageSetVismap(i, vmap); if (frameCounter == 0) { RMtexture *t = rmTextureNew(2); rmTextureSetFilterMode(t, GL_LINEAR, GL_LINEAR); rmTextureSetImages(t, &i, 1, 0); rmNodeSetSceneTexture(n, t); rmTextureDelete(t, RM_TRUE); } else { RMtexture *t; rmNodeGetSceneTexture(n,&t); rmTextureSetImages(t, &i, 1, 0); } rmImageDelete(i); } void myBuildObjs(RMnode *addTo) { RMvertex2D v[4] = {{-1.0,-1.0},{1.0,-1.0},{1.0,1.0},{-1.0,1.0}}; RMvertex2D tc[4] = {{0.0,0.0},{1.0,0.0},{1.0,1.0},{0.0,1.0}}; RMcolor4D bgColor={0.2, 0.1, 0.1, 1.0}; RMnode *myRoot = rmNodeNew("MyRoot", RM_RENDERPASS_2D, RM_RENDERPASS_ALL); RMnode *quadNode = rmNodeNew("QuadNode", RM_RENDERPASS_2D, RM_RENDERPASS_ALL); RMcamera2D *c = rmCamera2DNew(); RMprimitive *p = rmPrimitiveNew(RM_QUADS); rmPrimitiveSetVertex2D(p, 4, v, RM_COPY_DATA, NULL); rmPrimitiveSetTexcoord2D(p, 4, tc, RM_COPY_DATA, NULL); rmNodeAddPrimitive(quadNode, p); rmNodeAddChild(myRoot, quadNode); textureNode = quadNode; setTexture(textureNode, 0, frameCounter++); rmCamera2DSetExtents(c,-1.1,-1.1,1.1,1.1); rmNodeSetSceneCamera2D(myRoot, c); rmNodeSetSceneBackgroundColor(myRoot, &bgColor); rmCamera2DDelete(c); rmNodeAddChild(addTo, myRoot); } void myInitFunc(RMpipe *p, RMnode *n) { readData(datafilename); myBuildObjs(n); rmFrame(p, n); } void myRenderFunc(RMpipe *myPipe, RMnode *subTree) { rmFrame(myPipe, subTree); } void usage(char *s) { printf("usage: %s [-w imgWidthPixels ] [-h imgHeightPixels] [-c (use a HSV hue ramp in an RMvisMap to colorize the data, default is grayscale.) ]\n",s); } void parseArgs(int ac, char *av[], int *imgWidth, int *imgHeight) { int i; i = 1; while (i < ac) { if (strcmp(av[i],"-w") == 0) { i++; ac--; sscanf(av[i],"%d", imgWidth); } else if (strcmp(av[i],"-h") == 0) { i++; ac--; sscanf(av[i],"%d", imgHeight); } else if (strcmp(av[i],"-c") == 0) { do_color = 1; } else { usage(av[0]); exit(-1); } i++; } } int myIdleFunc(RMpipe *p, int pointerX, int pointerY) { /* * rather than display all slices of volume data, we only show * a portion of the dataset - between slices 100 and 212. The * other slices are all zeros, so the display is not very * interesting to look at in those regions. */ #define START 100 #define END 212 static int counter=START; if (counter >= END) counter = START; printf(" frame %d \n", frameCounter); setTexture(textureNode, counter++, frameCounter++); rmFrame(p, rmRootNode()); return 1; } #ifdef RM_WIN int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; HWND hWnd; void *fptr; int status; int imgWidth, imgHeight; RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */ RMenum targetPlatform = RM_PIPE_WGL; imgWidth = DEFAULT_IMAGE_WIDTH; imgHeight = DEFAULT_IMAGE_HEIGHT; parseArgs(__argc, __argv, &imgWidth, &imgHeight); #else /* assume RM_X */ int main(int argc, char *argv[]) { void *msg; /* needed for rmauxEventLoop win32/unix API consistency */ int status; int imgWidth, imgHeight; RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */ RMenum targetPlatform = RM_PIPE_GLX; imgWidth = DEFAULT_IMAGE_WIDTH; imgHeight = DEFAULT_IMAGE_HEIGHT; parseArgs(argc, argv, &imgWidth, &imgHeight); #endif /* * first stage of RM initialization. */ rmInit(); /* * create the rendering pipe. this step is required in both * Win32 and X. */ myPipe = rmPipeNew(targetPlatform); rmPipeSetProcessingMode(myPipe, processingMode); #ifdef RM_WIN { /* * Win32: when a window is created, we have to tell windows the * name of the "WndProc," the procedure that gets called by * windows with events (the event loop) (contrast to the X model * where the name of the event loop is not part of the window). * Since we're using RMaux, we know about the event handling * procedure named "rmauxWndProc" and we provide that here. */ fptr = (void *)(rmauxWndProc); hWnd = rmauxCreateW32Window(myPipe, NULL, /* no parent window */ 20,20,imgWidth,imgHeight,"RM for Windows", hInstance,fptr); if (hWnd == 0) exit(-1); /* * assign the new window handle to the rendering pipe. */ rmPipeSetWindow(myPipe,hWnd, imgWidth, imgHeight); } #endif #ifdef RM_X { Window w; w = rmauxCreateXWindow(myPipe, (Window)NULL, /* parent window */ 0,0,imgWidth,imgHeight, "RM for X-Windows","RM for X-Windows",RM_TRUE); /* * assign the window to the rendering pipe. */ rmPipeSetWindow(myPipe,w,imgWidth,imgHeight); } #endif /* * X-ism: once the window is created and assigned to the * rendering pipe, rmPipeMakeCurrent makes the OpenGL rendering context * current for the pipe+window combination. * * this step is required for X. in these demo programs, it is not * strictly required by Win32, as the newly created context is made * current as part of the OpenGL initialization sequence. */ rmPipeMakeCurrent(myPipe); rmauxSetInitFunc(myInitFunc); rmauxSetRenderFunc(myRenderFunc); rmauxSetIdleFunc(myPipe,myIdleFunc); /* * set key handler function so this prog will exit on "q" key. */ rmauxSetKeyFunc(myPipe, rmauxDefaultKeyFunc); rmauxEventLoop(myPipe,rmRootNode(), &msg); rmPipeDelete(myPipe); rmFinish(); return(1); }