Sophie

Sophie

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

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

/*
 * Copyright (C) 2000, 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: whack.c,v 1.6 2004/01/19 20:37:26 wes Exp $
 * $Revision: 1.6 $
 * $Name: OpenRM-1-5-2-RC1 $
 * $Log: whack.c,v $
 * Revision 1.6  2004/01/19 20:37:26  wes
 * Updated call that sets the context - was rmxPipeSetContext, is now
 * rmPipeSetContext.
 *
 * Set RM's frame rate to 60fps. You can now actually interact with these
 * programs on fast hardware.
 *
 * Revision 1.5  2003/08/06 19:04:01  wes
 * Updates for API changes present in OpenRM 1.5.0.
 *
 * Revision 1.4  2003/01/16 23:00:22  wes
 * Updated sources to reflect new organization of header files in OpenRM 1.5.0.
 *
 * Revision 1.3  2000/12/05 02:26:20  wes
 * Fix compile warnings.
 *
 * Revision 1.2  2000/12/05 02:20:37  wes
 * Use OpenRM v1.4.0-alpha-1 API.
 *
 * Revision 1.1.1.1  2000/09/02 17:23:53  wes
 * Initial entry.
 *
 */

/*
 * usage: whack [CAVE args]
 *
 * this demo program creates a "room" with textured walls, floor and
 * ceiling. at this time (9/2000), that's all there is. use the
 * CAVE simulator or live input devices to navigate around. in the
 * future, this demo will be more interesting.
 *
 * for more information about the CAVE library, visit the VRCO
 * website at http://www.vrco.com/.
 */

#include <stdio.h>
#include <unistd.h>
#include <rm/rm.h>   
#include <rm/rmaux.h>

#include <cave_ogl.h>

static RMpipe *myPipe;
static int frameRate=60; /* render at 60fps, could use a command line arg */

/*
 * it would be nice to obtain CAVE parms using CAVELib, but this
 * is not possible at this time. we need this information in order
 * to construct geometry that defines the walls of the CAVE.
 */

#define CAVEWIDTH 10.0
#define CAVEHEIGHT 10.0
#define CAVEDEPTH 10.0		/* not part of CAVELib */

#define CAVEORIGIN_X 5.0	/* origin in config file */
#define CAVEORIGIN_Y 0.0
#define CAVEORIGIN_Z 5.0

#if 0
/* will be used in a later version of this program */
static float caveWidth=CAVEWIDTH, caveHeight=CAVEHEIGHT;
static RMvertex3D caveOrigin = { CAVEORIGIN_X, CAVEORIGIN_Y, CAVEORIGIN_Z };
#endif
static RMvertex3D caveMin = {0.0F, 0.0F, 0.0F};
static RMvertex3D caveMax = {10.0F, 10.0F, 10.0F};
RMimage
*readAVSImage(const char *fname)
{
    RMimage *t;
    int w,h;
    int i,j,indx, indx2;
    FILE *f;
    unsigned char *static_image_data;
    float *static_image_data_float;

    f = fopen(fname,"r");
    if (f == NULL)
    {
	fprintf(stderr," can't open the AVS image file named <%s> \n",fname);
	return(NULL);
    }

    {
        unsigned char buf[4];
	read(fileno(f),(void *)buf,4);
	w = buf[3] | (buf[2] << 8);
	read(fileno(f),(void *)buf,4);
	h = buf[3] | (buf[2] << 8);
    }

    /* sanity check w,h */

    if ((w < 0) || (w > 4096) ||
	(h < 0) || (h > 4096))
    {
	fprintf(stderr," dubious image dimensions: %d, %d, aborting image read. \n",w,h);
	fclose(f);
	return(NULL);
    }

    static_image_data = (unsigned char *)malloc(sizeof(unsigned char)*w*h*4);

    /* this reads everything at once */
    read(fileno(f),(void *)static_image_data,w*h*4);

    fclose(f);

#define ONE_OVER_255 0.0039215686
    
    /* hack to change from ARGB to RGBA */
    indx = 0;
    indx2 = 3;
    for (i=0;i<w*h;i++)
    {
        unsigned char t;

	t = static_image_data[indx];
	for (j=0;j<3;j++)
	    static_image_data[indx+j] = static_image_data[indx+j+1];
	static_image_data[indx+3] = 0xFF;

	indx += 4;
    }

#define IMAGE_TYPE RM_UNSIGNED_BYTE
    
    if (IMAGE_TYPE == RM_FLOAT)
    {
	static_image_data_float = (float *)malloc(sizeof(float)*w*h*4);
	for (i=0;i<w*h*4;i++)
	    static_image_data_float[i] = (float)(static_image_data[i])*
		ONE_OVER_255;
    }

    /* 
     * problem in win-32 with RM_COPY_DATA: not sure what's up, top
     * part of image gets chewed off.
     *
     * problem w/RGB mode in glDrawPixels . it looks like it wants all
     * the image data to be 4-byte word aligned.
     */


    t = rmImageNew(2,w,h,1,RM_IMAGE_RGBA,
		   IMAGE_TYPE,
		   RM_COPY_DATA);  

    if (IMAGE_TYPE == RM_FLOAT)
    {
	rmImageSetPixelData(t, (void *)static_image_data_float,
			    RM_COPY_DATA,
			    NULL);
    }
    else
    {
	rmImageSetPixelData(t, (void *)static_image_data,
			    RM_COPY_DATA,
			    NULL);
    }

    rmImageMirror(t,RM_IMAGE_MIRROR_HEIGHT);

    return(t);
}

RMtexture *
loadTexture(const char *fname)
{
    RMtexture *t;
    RMimage *img;

    img = readAVSImage(fname);
    if (img == NULL)		/* error msg? */
	return(NULL);

    t = rmTextureNew(2);
    rmTextureSetImages(t,&img,1,RM_FALSE);
    return(t);
}

void
makeMarker(RMnode *addToNode,
	   float xval,
	   float yval,
	   float zval,
	   char *string)
{
    RMnode *n;
    RMprimitive *p;
    RMvertex3D v;
    char *strings[1];

    v.x = xval;
    v.y = yval;
    v.z = zval;

    n = rmNodeNew(string,RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
    p = rmPrimitiveNew(RM_TEXT);
    rmPrimitiveSetVertex3D(p, 1, &v, RM_COPY_DATA,NULL);
    strings[0] = string;
    rmPrimitiveSetText(p, 1, strings);
    
    rmNodeAddPrimitive(n,p);
    rmNodeAddChild(addToNode,n);
}

void
buildTexturedWall(RMnode *addToNode, /* result */
		  RMvertex3D *v, /* 4x 3D verts */
		  RMvertex3D *n, /* single 3D normals */
		  char *nname,	/* name for node */
		  char *fname)	/* file name for texture */
{
    RMnode *wallNode;
    RMprimitive *wallPrim;
    RMtexture *t;
    RMvertex3D n2[4];
    RMvertex2D tc[4];
    
    wallNode = rmNodeNew(nname, RM_RENDERPASS_3D,
			 RM_RENDERPASS_OPAQUE);
    wallPrim = rmPrimitiveNew(RM_QUADS);

    n2[0] = n2[1] = n2[2] = n2[3] = *n;
    
    rmPrimitiveSetVertex3D(wallPrim,4,v,RM_COPY_DATA,NULL);
    rmPrimitiveSetNormal3D(wallPrim,4,n2,RM_COPY_DATA,NULL);
    
    tc[0].x = tc[0].y = 0.0;
    tc[1].x = 1.0;
    tc[1].y = 0.0;
    tc[2].x = tc[2].y = 1.0;
    tc[3].x = 0.0;
    tc[3].y = 1.0;
    
    rmPrimitiveSetTexcoord2D(wallPrim,4,tc,RM_COPY_DATA,NULL);

    rmNodeAddPrimitive(wallNode,wallPrim);
    rmNodeAddChild(addToNode, wallNode);
	
    t = loadTexture(fname);
    rmNodeSetSceneTexture(wallNode, t);
    rmTextureDelete(t, RM_TRUE);
}

void
buildAndTextureWalls(RMnode *addToNode)
{
    RMvertex3D cmin, cmax;
    RMvertex3D wmin, wmax;
    RMnode *wallsRoot;
    RMvertex3D v[4], n[4];

    /* compute the corners (min/max) of the physical cave - we want
     our virtual walls to correspond exactly with the physical dislay.
     it would be nice if we could obtain the necessary info directly
     from CAVELib - until that time, the constants are defined above and
     will require manual modification if they don't match the values
     in the CAVEConfig file. the values above were chosen to match
     those that are the defaults. */

    cmin = caveMin;
    cmax = caveMax;

    wallsRoot = rmNodeNew("wallsRoot", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);

    wmin = cmin;
    wmax = cmax;
    
    /* front wall, at z=0 plane */
    
    v[0] = wmin;
    v[1] = wmin;
    v[1].x = wmax.x;
    v[2] = v[1];
    v[2].y = wmax.y;
    v[3] = v[2];
    v[3].x = wmin.x;
    
    n[0].x = n[0].y = 0.0F;
    n[0].z = 1.0F;

    buildTexturedWall(wallsRoot, v, n, "frontWall","textures/front.x");

    /* back wall, at z=10 plane */
    
    v[0] = wmax;
    v[0].y = wmin.y;
    v[1] = v[0];
    v[1].x = wmin.x;
    v[2] = v[1];
    v[2].y = wmax.y;
    v[3] = v[2];
    v[3].x = wmax.x;
    
    n[0].x = n[0].y = 0.0F;
    n[0].z = -1.0F;

    buildTexturedWall(wallsRoot, v, n, "frontWall","textures/back.x");

    /* floor, at y=0 plane*/
    
    v[0] = wmin;
    v[0].z = wmax.z;

    v[1] = v[0];
    v[1].x = wmax.x;

    v[2] = v[1];
    v[2].z = wmin.z;

    v[3] = v[2];
    v[3].x = wmin.x;

    n[0].x = n[0].z = 0.0F;
    n[0].y = 1.0F;

    buildTexturedWall(wallsRoot, v, n, "floor","textures/floor.x");

    /* ceiling, at y=10 plane*/

    v[0] = wmin;
    v[0].y = wmax.y;

    v[1] = v[0];
    v[1].x = wmax.x;

    v[2] = v[1];
    v[2].z = wmax.z;

    v[3] = v[2];
    v[3].x = wmin.x;

    n[0].x = n[0].z = 0.0F;
    n[0].y = -1.0F;

    buildTexturedWall(wallsRoot, v, n, "floor","textures/bigsky.x");

    /* build left wall , at x=0 plane*/

    v[0] = wmin;
    v[0].z = wmax.z;

    v[1] = v[0];
    v[1].z = wmin.z;

    v[2] = v[1];
    v[2].y = wmax.y;

    v[3] = v[2];
    v[3].z = wmax.z;

    n[0].y = n[0].z = 0.0F;
    n[0].x = 1.0F;

    buildTexturedWall(wallsRoot, v, n, "floor","textures/left.x");

    /* build right wall , at x=10 plane*/

    v[0] = wmin;
    v[0].x = wmax.x;

    v[1] = v[0];
    v[1].z = wmax.z;

    v[2] = v[1];
    v[2].y = wmax.y;

    v[3] = v[2];
    v[3].z = wmin.z;

    n[0].y = n[0].z = 0.0F;
    n[0].x = -1.0F;

    buildTexturedWall(wallsRoot, v, n, "rightWall","textures/right.x");

    /* these text strings are added to the scene as a "sanity check" */
    makeMarker(addToNode, 0.0, 0.0, 0.0, "0 0 0");
    makeMarker(addToNode, 10.0, 0.0, 10.0, "10 0 10");
    makeMarker(addToNode, 0.0, 0.0, 10.0, "0 0 10");

    rmNodeAddChild(addToNode, wallsRoot);
}

void
setArenaLighting(RMnode *addToNode)
{
    RMlight *l0;
    RMcolor4D diffuse = {0.9, 0.9, 0.9, 1.0};
    RMcolor4D defAmbient = {0.3, 0.3, 0.3, 1.0};
    RMvertex3D pos    = {0.0, 5.0, 0.0};
    RMlightModel *lm;

    l0 = rmLightNew();
    rmLightSetType(l0, RM_LIGHT_POINT);
    rmLightSetColor(l0, NULL, &diffuse, &diffuse);
    rmLightSetXYZ(l0, &pos);

    rmNodeSetSceneLight(addToNode, RM_LIGHT0, l0);
    rmLightDelete(l0);

    lm = rmLightModelNew();
    rmLightModelSetAmbient(lm, &defAmbient);
    rmLightModelSetTwoSided(lm, RM_FALSE);
    rmLightModelSetLocalViewer(lm, RM_FALSE);
    rmNodeSetSceneLightModel(addToNode, lm);
    rmLightModelDelete(lm);
}

void
buildInitialSceneGraph(void)
{

    RMnode *MyRoot = rmNodeNew("MyRoot", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
    /* obtain the coords of the CAVE walls, and build a set of
     6 walls that are textured. */
    
    buildAndTextureWalls(MyRoot);
    
    setArenaLighting(rmRootNode());

    {
	RMcolor4D c={0.2, 0.2, 0.3, 1.0};
	float one = 1.0F;

	rmNodeSetSceneBackgroundColor(MyRoot, &c);
	rmNodeSetSceneDepthValue(MyRoot, &one);
    }

    {
	RMvertex3D v;
	
	v.x = -CAVEORIGIN_X;
	v.y = -CAVEORIGIN_Y;
	v.z = -CAVEORIGIN_Z;
	rmNodeSetTranslateVector(MyRoot, &v);
    }

    rmNodeAddChild(rmRootNode(), MyRoot);

    rmNodeSetSceneViewport(rmRootNode(), NULL);
}

void
myInitPipe()
{
    int myWidth, myHeight, myOriginX, myOriginY;
    myPipe = rmPipeNew(RM_PIPE_GLX);

    /*
     * we have to manually assign needed parameters to the Pipe
     * using the values set up by CAVElib.
     */

    /* want a channel format that doesn't blow the matrix stack
     upon entry. */
    rmPipeSetChannelFormat(myPipe, RM_MONO_CHANNEL);
    rmPipeSetInitMatrixStackMode(myPipe, RM_FALSE);
    rmPipeSetFrameRate(myPipe, frameRate);

    /* turn off swapbuffers - CAVElib handles that. */
    rmPipeSetSwapBuffersFunc(myPipe, NULL);

    /* obtain the OpenGL context from CAVElib, assign that to the pipe */
    rmPipeSetContext(myPipe, CAVEGLXContext());
    rmxPipeSetDisplay(myPipe, CAVEXDisplay());

    /* obtain and assign window geometry */
    CAVEGetWindowGeometry(&myOriginX, &myOriginY, &myWidth, &myHeight);
    rmPipeSetWindow(myPipe, CAVEXWindow(), myWidth, myHeight);
	
    rmPipeMakeCurrent(myPipe);
}

void
appInitGL(void)
{
    /* each PE initializes it's own OpenRM */
    rmInit();

    /* initialize the RMpipe */
    myInitPipe();
    
    /* build the scene graph */
    buildInitialSceneGraph();
}

void
appDrawFunc(void)
{
    rmFrame(myPipe, rmRootNode());
}

int
main(int argc,
     char *argv[])
{
    int numPipes;
    extern void caveDrawFunc(void);
    
    CAVEConfigure(&argc, argv, NULL);
    
    numPipes = CAVENumPipes();

    CAVEInit();			/* app goes parallel here */
 
    CAVEInitApplication(appInitGL, 0); /* each CAVE pipe or channel has
					  some gfx initialization code. */

    CAVEDisplay(appDrawFunc, 0);	/* parallel draw */

/*    CAVEFrameFunction(mySpinFunc, 0);  no per-frame func at this time */

    while (!CAVEgetbutton(CAVE_ESCKEY))
	usleep(1000);		/* sleep 1000 microseconds (1msec) */
    
    CAVEExit();
    return(0);
}