/* * Copyright (C) 1997-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: jack.c,v 1.11 2003/04/13 18:13:23 wes Exp $ * $Revision: 1.11 $ * $Name: OpenRM-1-5-2-RC1 $ * $Log: jack.c,v $ * Revision 1.11 2003/04/13 18:13:23 wes * Updated copyright dates. * * Revision 1.10 2003/01/27 05:07:07 wes * Changes to RMpipe initialization sequence APIs. Tested for GLX, but not WGL. * * Revision 1.9 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.8 2002/06/17 00:38:31 wes * replace rmSubtreeFrame with rmFrame. * * Revision 1.7 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.6 2001/06/03 19:44:05 wes * Add calls to new rmaux routines to handle window resize events, and * for keyboard event handling. * * Revision 1.5 2001/03/31 16:55:18 wes * Added procmode.h, which defines an RMpipe processing mode used in * most demonstration programs. The default processing mode is * RM_PIPE_MULTISTAGE_VIEW_PARALLEL. * * Revision 1.4 2000/12/02 17:24:32 wes * Version 1.4.0-alpha-1 checkin. See the RELEASENOTES file for * a summary of changes. With this checkin, these demo programs * are no longer compatible with versions of the OpenRM API that * are pre-1.4.0. * * Revision 1.3 2000/08/28 01:38:18 wes * Updated rmaux* interfaces - rmauxEventLoop now takes two additional * parameters (keypress and window resize app callbacks); replaced * rmauxUI with rmauxSetGeomTransform and, where appropriate, * rmauxSetCamera3DTransform. * * Revision 1.2 2000/04/16 14:42:28 wes * Changed "1" to RM_TRUE for variable "managed," passed to rmauxCreateXWindow. * * Revision 1.1.1.1 2000/02/28 21:55:30 wes * OpenRM 1.2 Release * * Revision 1.10 2000/02/28 17:21:55 wes * RM 1.2, pre-OpenRM * */ #include <rm/rm.h> #include <rm/rmaux.h> #include "procmode.h" static RMpipe *lone_pipe=NULL; static RMnode *MyRoot; int img_width=400,img_height=300; RMenum static_stereo_format; void my_set_scene(RMnode *camNode, RMenum stereo_format) { /* * here, we compute the camera parameters such that all of * the geometry is visible. */ RMcamera3D *c=rmCamera3DNew(); rmDefaultCamera3D(c); /* assign it some default parameters */ /* adjust the "default" camera based upon MyRoot's geometry */ rmCamera3DComputeViewFromGeometry(c,MyRoot,img_width,img_height); if (stereo_format != RM_MONO_CHANNEL) { rmCamera3DSetStereo(c,RM_TRUE); rmCamera3DSetEyeSeparation(c,2.5F); rmCamera3DSetFocalDistance (c,0.707F); } rmNodeSetSceneCamera3D(camNode,c); rmCamera3DDelete(c); /* * make the background black for fun */ { RMcolor4D c; c.r = c.g = c.b = c.a = 0.0; /* * assign a background color to take effect at "MyRoot" */ rmNodeSetSceneBackgroundColor(MyRoot,&c); } /* use RM's default lighting model, apply at rmRootNode() */ rmDefaultLighting(camNode); } void my_sphere(RMnode *addto, float cx, float cy, float cz, float radius, RMcolor3D *color) { RMprimitive *sprim; RMvertex3D v; v.x = cx; v.y = cy; v.z = cz; sprim = rmPrimitiveNew(RM_SPHERES); rmPrimitiveSetVertex3D(sprim,1,&v,RM_COPY_DATA,NULL); rmPrimitiveSetRadii(sprim, 1, &radius, RM_COPY_DATA, NULL); if (color != NULL) rmPrimitiveSetColor3D(sprim, 1, color, RM_COPY_DATA, NULL); rmPrimitiveSetModelFlag(sprim,RM_SPHERES_32); rmNodeAddPrimitive(addto, sprim); } void my_cylinder(RMnode *addto, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z, float radius) { RMvertex3D v[2]; RMprimitive *cprim; v[0].x = p1x; v[0].y = p1y; v[0].z = p1z; v[1].x = p2x; v[1].y = p2y; v[1].z = p2z; cprim = rmPrimitiveNew(RM_CYLINDERS); rmPrimitiveSetVertex3D(cprim,2,v,RM_COPY_DATA,NULL); rmPrimitiveSetRadii(cprim, 1, &radius, RM_COPY_DATA, NULL); rmNodeAddPrimitive(addto, cprim); } void my_cone(RMnode *addto, float p1x, float p1y, float p1z, float p2x, float p2y, float p2z, float radius, RMcolor3D *color) { RMprimitive *cprim; RMvertex3D v[2]; v[0].x = p1x; v[0].y = p1y; v[0].z = p1z; v[1].x = p2x; v[1].y = p2y; v[1].z = p2z; cprim = rmPrimitiveNew(RM_CONES); rmPrimitiveSetVertex3D(cprim,2,v,RM_COPY_DATA,NULL); rmPrimitiveSetRadii(cprim, 1, &radius, RM_COPY_DATA, NULL); if (color != NULL) rmPrimitiveSetColor3D(cprim, 1, color, RM_COPY_DATA, NULL); rmNodeAddPrimitive(addto, cprim); } void my_build_objs(void) { RMcolor3D color; /* from the cones.c in the x-demos distribution*/ MyRoot = rmNodeNew("MyRoot",RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE); /* build the jack */ /* the center sphere should be red. */ color.r = 1.0; color.g = color.b = 0.0; my_sphere(MyRoot,0.0F, 0.0F, 0.0F, 1.0F,&color); /* a blue sphere at (5,0,0) */ color.r = color.g = 0.0; color.b = 1.0; my_sphere(MyRoot,5.0F, 0.0F, 0.0F, 1.0F,&color); /* a white sphere opposite blue sphere at (-5, 0, 0) */ my_sphere(MyRoot,-5.0F, 0.0F, 0.0F, 1.0F,NULL); /* a green sphere at (0,0,5) */ color.r = color.b = 0.0; color.g = 1.0; my_sphere(MyRoot,0.0F, 0.0F, 5.0F, 1.0F,&color); /* a white sphere opposite the green sphere at (0,0,-5) */ my_sphere(MyRoot,0.0F, 0.0F, -5.0F, 1.0F,NULL); my_cylinder(MyRoot,0.0F, 0.0F, 0.0F, 5.0F, 0.0F, 0.0F, 0.3F); my_cylinder(MyRoot,0.0F, 0.0F, 0.0F, -5.0F, 0.0F, 0.0F, 0.3F); my_cylinder(MyRoot,0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 5.0F, 0.3F); my_cylinder(MyRoot,0.0F, 0.0F, 0.0F, 0.0F, 0.0F, -5.0F, 0.3F); { RMcolor3D red={1.0,0.0,0.0}; /* one cone is red, one is white (default color) */ my_cone(MyRoot,0.0F,0.0F,0.0F,0.0F,6.0F,0.0F,0.5F,NULL); my_cone(MyRoot,0.0F,0.0F,0.0F,0.0F,-6.0F,0.0F,0.5F,&red); } rmNodeComputeBoundingBox(MyRoot); rmNodeAddChild(rmRootNode(),MyRoot); rmNodeUnionAllBoxes(rmRootNode()); rmNodeComputeCenterFromBoundingBox(rmRootNode()); } 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(lone_pipe, rmRootNode()); } void myinitfunc(RMpipe *p, RMnode *n) { my_build_objs(); my_set_scene(rmRootNode(), 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); /* * set handler to reset aspect ratio when the window is resized. */ rmauxSetResizeFunc(p, rmRootNode(), rmauxDefaultResizeFunc); /* rmStatsComputeDemography(rmRootNode()); */ if (rmPipeProcessingModeIsMultithreaded(p) == RM_TRUE) rmFrame(p, rmRootNode()); rmFrame(p,rmRootNode()); } 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; RMenum channelFormat; RMenum targetPlatform = RM_PIPE_WGL; void *fptr; #else /* assume RM_X */ int main() { RMenum channelFormat; RMenum targetPlatform = RM_PIPE_GLX; void *msg; /* needed for rmauxEventLoop win32/unix API consistency */ #endif int status; RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */ /* * 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. */ channelFormat = RM_MONO_CHANNEL; /* * first stage of RM initialization. */ rmInit(); /* * create the rendering pipe. this step is required in both * Win32 and X. */ lone_pipe = rmPipeNew(targetPlatform); rmPipeSetProcessingMode(lone_pipe, 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(lone_pipe, NULL, /* no parent window */ 20,20,img_width,img_height,"RM for Windows", hInstance,fptr); if (hWnd == 0) exit(-1); /* * assign the new window handle to the rendering pipe. */ rmPipeSetWindow(lone_pipe,hWnd, img_width, img_height); } #endif #ifdef RM_X { Window w; int managed = RM_TRUE; w = rmauxCreateXWindow(lone_pipe, (Window)NULL, /* parent window */ 0,0,img_width,img_height, "RM for X-Windows","icon-title",managed); /* * assign the window to the rendering pipe. */ rmPipeSetWindow(lone_pipe,w,img_width,img_height); } #endif /* * specify the name of the "init" function. the "init" function is * mandatory in the Win32 world, and optional in the X world. * * in Win32, we don't want to call RM services until OpenGL is * ready. we can be assured of readiness by using an init function * with RMaux. * * in X, at this point, the window is mapped and OpenGL is ready, * and we could call our init function directly. */ rmauxSetInitFunc(myinitfunc); /* uncomment this next line if you want the object to rotate by itself while the user is idle. */ /* rmauxSetIdleFunc(lone_pipe,my_idle_func); */ /* * X-ism: once the window is created and assigned to the * rendering pipe, rmUsePipe 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(lone_pipe); rmauxSetRenderFunc(myrenderfunc); /* * set key handler function so this prog will exit on "q" key */ rmauxSetKeyFunc(lone_pipe, rmauxDefaultKeyFunc); rmauxEventLoop(lone_pipe,rmRootNode(), &msg); rmPipeDelete(lone_pipe); rmFinish(); #ifdef RM_WIN return( msg.wParam ); #else return(1); #endif }