Sophie

Sophie

distrib > Mandriva > 2007.0 > i586 > media > contrib-release > by-pkgid > 8079d983ecf371717db799dd75bd56c2 > files > 149

libopenrm1-1.5.2-2mdv2007.0.i586.rpm

/*
 * 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: offscreen.c,v 1.9 2003/07/25 21:56:43 wes Exp $
 * $Revision: 1.9 $
 * $Name: OpenRM-1-5-2-RC1 $
 * $Log: offscreen.c,v $
 * Revision 1.9  2003/07/25 21:56:43  wes
 * Bug fix: post-render callback wasn't being assigned under Win32.
 *
 * Revision 1.8  2003/04/13 18:13:23  wes
 * Updated copyright dates.
 *
 * Revision 1.7  2003/01/27 05:07:07  wes
 * Changes to RMpipe initialization sequence APIs. Tested for GLX, but not WGL.
 *
 * Revision 1.6  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.5  2002/06/17 00:39:58  wes
 * replaced rmSubtreeFrame with rmFrame.
 *
 * Revision 1.4  2001/10/15 00:23:52  wes
 * Use new rmPipeSetOffscreenWindow() routine.
 *
 * Revision 1.3  2001/07/15 22:33:19  wes
 * Added rmPipeDelete to the end of all demo progs. For those that use
 * an initfunc, added a new RMnode * parm (which is unused, except for rm2screen).
 *
 * Revision 1.2  2001/06/03 19:41:18  wes
 * Replace call to create an AVS format image with a call to
 * create a JPEG image.
 *
 * Revision 1.1  2001/03/31 17:26:14  wes
 * Initial entry.
 *
 */

#include <rm/rm.h>
#include <rm/rmaux.h>
#include <rm/rmv.h>
#include "libdio.h"
#include "procmode.h"

int imgWidth=800,imgHeight=600;

static char MyRootName[]={"MyRoot"};
static RMnode *MyRoot;
char datafilename[256]={"data/volume.dio"};
dioDataObject *mydataobj=NULL;
int do_color=0;
int do_print=0;
int vis_technique=0;
int my_linewidth = RM_LINEWIDTH_MEDIUM;
int my_linestyle = RM_LINES_SOLID;

float isolevel=0.5;

int           use_secondary=0;
dioDataObject *secondary=NULL;
RMvisMap      *vmap=NULL;

#define DO_OFFSCREEN 1

/*
 * Colorization notes:
 * 1. when a secondary dataset is provided, the isosurface will be
 *    vertex-colorized by:
 * 2. at each isosurface triangle vertex, the rmv routine that generates
 *    the isosurface will invoke the app callback to retrieve 
 *    data values from the secondary dataset. the RGB(A) color value
 *    from the visualization colormap that corresponds to the data value
 *    from the secondary dataset will be used as the vertex color.
 * 3. since it is an app callback that provides the secondary data values
 *    via a callback, there is no restriction that says the actual
 *    size, or even dimensionality, of the secondary dataset must be
 *    the same as the primary dataset.
 * 4. this demo maps the min/max of the secondary data set to the min/max
 *    transfer function values.
 * 5. this demo uses the primary dataset as the source of the secondary
 *    dataset. that means that we should see an isosurface of constant
 *    color, where the color will essentially be a function of the
 *    isocontouring level.
 */

void
usage(char *av[])
{
    char buf[256];
    sprintf(buf," usage: %s [-i datafilename (defaults to data/volume.dio) [-w imgWidth] [-h imgHeight] [-p (print the scene graph to stderr)] [-l isolevel (isocontouring level, default is 0.5, use a value in range 0..1.0 with the default data set)] \n",av[0]);

#ifdef RM_WIN
    MessageBox(NULL,buf,"vis3d",MB_OK);
#else
    fprintf(stderr,"%s",buf);
#endif
}

void
parse_args(int ac,
	   char *av[])
{
    int i;

    i = 1;
    while (i < ac)
    {
	if (strcmp(av[i],"-w") == 0)
	{
	    i++;
	    sscanf(av[i],"%d",&imgWidth);
	}
	else if (strcmp(av[i],"-h") == 0)
        {
	    i++;
	    sscanf(av[i],"%d",&imgHeight);
	}
	else if (strcmp(av[i],"-i") == 0)
	{
	    i++;
	    strcpy(datafilename,av[i]);
	}
	else if (strcmp(av[i],"-2") == 0)
        {
	    use_secondary=1;
	}
	else if (strcmp(av[i],"-l") == 0)
        {
	    i++;
	    sscanf(av[i],"%f",&isolevel);
	}
	else if (strcmp(av[i],"-c") == 0)
	{
	    do_color=1;
	}
	else if (strcmp(av[i],"-p") == 0)
	    do_print = 1;
	else
	{
	    usage(av);
	    exit(-1);
	}
	i++;
    }
}


void
my_read_data(char *datafilename)
{
    mydataobj = dioReadDataObject(datafilename);
    if (mydataobj == NULL)
    {
	fprintf(stderr," error reading input data file. exiting. \n");
	exit(-1);
    }
    dioObjectConditioner(mydataobj);
}

void
my_set_scene(int stereo_format)
{
    RMcamera3D *c=rmCamera3DNew();
    
    rmDefaultCamera3D(c);		/* assign it some default values. */
    
    rmCamera3DComputeViewFromGeometry(c,MyRoot, imgWidth, imgHeight); 

    if (stereo_format != RM_MONO_CHANNEL)
    {
	rmCamera3DSetStereo(c,RM_TRUE);
	rmCamera3DSetEyeSeparation(c,2.5F);
	rmCamera3DSetFocalDistance (c,0.707F);
	
    }

    /* add the 3D camera as a scene parameter to rmRootNode() */
    rmNodeSetSceneCamera3D(rmRootNode(),c); 

    rmCamera3DDelete(c);


    /* use RM's default lighting model */
    rmDefaultLighting(rmRootNode()); 
    
}

/*
 * the following two routines are the interface between the RMV
 * vis tools and the local data model. RMV wants us to supply routines
 * which will tell the vis tool what the (x,y,z) point is at some grid
 * location, and what the data point is at some grid location.
 *
 * the local data model is very simple, so we can make simplifying
 * assumptions resulting in very terse routines.
 */

RMvertex3D
mygridfunc_uvw(int i,
	       int j,
	       int k,
	       int isize,
	       int jsize,
	       int ksize,
	       float *baseX,
	       float *baseY,
	       float *baseZ)
{
    /*
     * tell RMV what this grid (x,y,z) point is at location (i,j,k).
     * we assume the data model is sufficiently intelligent to know
     * it's own dimensions, and is capable of dealing with a three-dimensional
     * indexing system.
     *
     * we assume that the "i" index maps to width, and that "j"
     * maps to height, and k maps to depth in the local data model.
     */
    RMvertex3D temp3d;
    int indx;

    /*    indx = mydataobj->width * j + i; */
/*    indx = mydataobj->dims[0] * j + i + mydataobj->dims[0]*mydataobj->dims[1]*k; */
    indx = isize * j + i + isize*jsize*k;
    
    temp3d.x = baseX[indx];
    temp3d.y = baseY[indx];
    temp3d.z = baseZ[indx];
    
    return(temp3d);
}

float
mydatafunc_uvw(int i,
	       int j,
	       int k,
	       int isize,
	       int jsize,
	       int ksize,
	       float *baseData)
{
    /*
     * tell RMV what the data value is at grid location (i,j,k). we
     * assume an n-dimensional array can be accesses as if it
     * were a one-d array.
     */
    int indx;

/*    indx = mydataobj->dims[0] * j + i + mydataobj->dims[0]*mydataobj->dims[1]*k; */
    indx = isize * j + i + isize*jsize*k;
    return(baseData[indx]);
}


void
my_build_objs(void)
{
    RMnode *visnode;

    MyRoot = rmNodeNew(MyRootName,RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
    rmNodeAddChild(rmRootNode(),MyRoot);

    visnode = rmNodeNew("vis",RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
    
    rmvK3MarchingCubes(mygridfunc_uvw,
		       mydatafunc_uvw,
		       /* note this is a hack - we should really be using
			a secondary dataset that is different from the
			primary dataset. since we're just reusing the
			primary dataset, what we'll get is a constant-
			colored isosurface, and the color changes when
			we change the isocontouring level via the command line*/
		       (secondary != NULL) ? mydatafunc_uvw : NULL,
		       vmap,
		       mydataobj->width,
		       mydataobj->height,
		       mydataobj->depth,
		       isolevel,
		       visnode,
		       mydataobj->xcoords,
		       mydataobj->ycoords,
		       mydataobj->zcoords,
		       mydataobj->rawdata);

    
    rmNodeAddChild(MyRoot,visnode); 

    /*
     * set the bounding box for the visnode as a function of
     * the extents of the underlying grid, not the extents of
     * the derived isosurface.
     */
    
    rmNodeSetBoundingBox(visnode,
			 (RMvertex3D *)&(mydataobj->corners[0]),
			 (RMvertex3D *)&(mydataobj->corners[1]));
    rmNodeComputeCenterFromBoundingBox(visnode);

    rmNodeUnionAllBoxes(rmRootNode());

    rmNodeComputeCenterFromBoundingBox(MyRoot);

    {
	RMcolor4D bgcolor={0.2,0.2,0.3,1.0};
	/*
	 * assign a background color to take effect at "MyRoot"
	 */
	rmNodeSetSceneBackgroundColor(MyRoot,&bgcolor);
    }

    dioDeleteDataObject(mydataobj);

}

void
my_idle_func(RMpipe *p,
	     int ix,
	     int iy)
{
    RMmatrix m,old;
    double d,c,s;
    rmMatrixIdentity(&m);
    d = RM_DEGREES_TO_RADIANS(1.0);
    c = cos(d);
    s = sin(d);
    m.m[0][0] = m.m[2][2] = c;
    m.m[0][2] = -s;
    m.m[2][0] = s;

    if (rmNodeGetRotateMatrix(MyRoot,&old) == RM_WHACKED)
	rmMatrixIdentity(&old);
    rmMatrixMultiply(&old,&m,&old);
    rmNodeSetRotateMatrix(MyRoot,&old);
    
    rmFrame(p, rmRootNode());
}

void
setup_secondary_dataobj()
{
    secondary = mydataobj;
    vmap = rmDefaultVismap();
    rmVismapSetTfMin(vmap,mydataobj->datamin);
    rmVismapSetTfMax(vmap,mydataobj->datamax);
}

void
myDumpImageFunc(const RMimage *img,
		RMenum whichPass)
{
    char fname[]={"offscreen.jpg"};
    
    printf(" Writing JPEG image file named %s ...", fname);
    fflush(stdout);

    rmiWriteJPEG(fname, 100, img);

    printf(" ..done \n");
    fflush(stdout);
}

void
myinitfunc(RMpipe *p)
{
    my_read_data(datafilename);

    if (use_secondary == 1)
	setup_secondary_dataobj();
    
    my_build_objs();
    my_set_scene(rmPipeGetChannelFormat(p));
    
    /*
     * set up the event handler to apply geometric transformations at
     * MyRoot. note that the lights and cameras are placed at rmRootNode().
     * therefore, the rotations & scaling applied at MyRoot do not affect
     * the cameras & lights since they are at a higher level in the
     * scene graph than MyRoot.
     */
    rmauxSetGeomTransform(MyRoot,p);
    rmauxSetCamera3DTransform(rmRootNode(), p);


    if (do_print == 1)		/* won't see output in win32 unless you change
				 NULL to a char string with a filename, then
				 the output will be written in ASCII format
				 to that file. */
	rmPrintSceneGraph(rmRootNode(),RM_PRINT_VERBOSE,NULL);

}

void
myrenderfunc(RMpipe *p, RMnode *n)
{
    rmStatsStartTime();

    rmFrame(p, n);

    rmStatsEndTime();
    rmStatsPrint();
}

#ifdef RM_WIN
int WINAPI WinMain (HINSTANCE hInstance,
		    HINSTANCE hPrevInstance,
                    LPSTR lpszCmdLine, int nCmdShow)
{
    MSG      msg; 
    HWND     hWnd; 
    void *fptr;
    int status;
    RMpipe *lone_pipe = NULL;
    RMenum targetPlatform = RM_PIPE_WGL;
    RMenum processingMode = RM_PIPE_MULTISTAGE; /* don't use MP mode! */
    RMenum channelFormat;

    parse_args(__argc, __argv);

#else  /* assume RM_X */
int
main(int ac,
     char *av[])
{
    int status;
    RMpipe *lone_pipe = NULL;
    RMenum processingMode = RM_PIPE_MULTISTAGE; /* don't use MP mode! */
    RMenum targetPlatform = RM_PIPE_GLX;
    RMenum channelFormat;
    void *msg;			/* needed for rmauxEventLoop
				 win32/unix API consistency */
    parse_args(ac, av);
#endif

    /* 
     * pick a stereo format:
     * RM_MONO_CHANNEL - plain old single-view
     * RM_REDBLUE_STEREO_CHANNEL - left channel in red, right channel in cyan
     * RM_BLUERED_STEREO_CHANNEL - left in cyan, right in red
     * RM_MBUF_STEREO_CHANNEL - multibuffered stereo, requires special
     *    hardware. 
     */
#if DO_OFFSCREEN
    channelFormat = RM_OFFSCREEN_MONO_CHANNEL;
#else
    channelFormat = RM_MONO_CHANNEL;
#endif
    

    /* 
     * first stage of RM initialization.
     */
    rmInit();

    /* 
     * create the rendering pipe. this step is required in both
     * Win32 and X.
     */
    lone_pipe = rmPipeNew(targetPlatform);
    rmPipeSetChannelFormat(lone_pipe, channelFormat);
    
    rmPipeSetProcessingMode(lone_pipe, processingMode);

#if DO_OFFSCREEN

#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 = rmauxCreateOffscreenDrawable(lone_pipe,
					    imgWidth,imgHeight,16,
					    hInstance,fptr);
	if (hWnd == 0)
	  exit(-1);

	/* 
	 * assign the new window handle to the rendering pipe.
	 */
	rmPipeSetWindow(lone_pipe,hWnd, imgWidth, imgHeight);

    }
#endif
#ifdef RM_X
    {
	GLXPixmap glxp;
	glxp = rmauxCreateOffscreenDrawable(lone_pipe,
					    imgWidth, imgHeight,
					    DefaultDepth(rmxPipeGetDisplay(lone_pipe), DefaultScreen(rmxPipeGetDisplay(lone_pipe))));

	/* 
	 * assign the offscreen window to the rendering pipe.
	 */
	rmPipeSetOffscreenWindow(lone_pipe, glxp, imgWidth, imgHeight);
    }
#endif
    rmPipeSetPostRenderFunc(lone_pipe, myDumpImageFunc);
    
#else  /* do interactive stuff */
    
#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(lone_pipe,
			       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(lone_pipe,hWnd, imgWidth, imgHeight);
    }
#endif
#ifdef RM_X
    {
	Window w;
	int managed = RM_TRUE;

	w = rmauxCreateXWindow(lone_pipe,
			       (Window)NULL, /* parent window */
			       0,0,imgWidth,imgHeight,
			       "RM for X-Windows","icon-title",managed);
	/* 
	 * assign the window to the rendering pipe.
	 */

	rmPipeSetWindow(lone_pipe,w,imgWidth,imgHeight);
    }
#endif
    
#endif

    rmPipeMakeCurrent(lone_pipe);

    myinitfunc(lone_pipe);

#if DO_OFFSCREEN
    rmFrame(lone_pipe, rmRootNode());
#else

    rmFrame(lone_pipe, rmRootNode());
    rmauxSetKeyFunc(lone_pipe, rmauxDefaultKeyFunc);
    rmauxSetRenderFunc(myrenderfunc);
    rmauxEventLoop(lone_pipe,rmRootNode(), &msg);
#endif

    rmPipeDelete(lone_pipe);
    rmFinish();

#ifdef RM_WIN
    return( msg.wParam );
#else
    return(1);
#endif
}