home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- *
- * File : dosview.c
- *
- * Abstract : A very simple, sample RenderWare application for
- * MS-Dos / PC-Dos. This application has very little
- * functionality, but is simply intended as a demonstration
- * of how to use the RenderWare API.
- *
- * This application had been written to be compatible with
- * both the fixed and floating-point versions of the
- * RenderWare library, i.e., it uses the macros CREAL,
- * INT2REAL, RAdd, RDiv, RSub etc. If your application is
- * intended for the floating-point version of the library
- * only these macros are not necessary.
- *
- * Please note that this application is intended for
- * demonstration purposes only. No support will be
- * provided for this code and it comes with no warranty.
- *
- * This file is a product of Criterion Software Ltd.
- *
- * This file is provided as is with no warranties of any kind and is
- * provided without any obligation on Criterion Software Ltd. or
- * Canon Inc. to assist in its use or modification.
- *
- * Criterion Software Ltd. and Canon Inc. will not, under any
- * circumstances, be liable for any lost revenue or other damages arising
- * from the use of this file.
- *
- * Copyright (c) 1991, 1992, 1993. Canon Inc.
- * All Rights Reserved.
- *
- **********************************************************************/
-
- /****************************************************************************
- Includes
- */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
-
- #include <i86.h>
- #include <math.h> /* Required for floating point */
-
- #include "rwlib.h"
- #include "rwdos.h"
- #include "doswrap.h"
-
- /****************************************************************************
- Types
- */
-
- /**********************************************************************
- *
- * Application constants.
- *
- **********************************************************************/
-
- #define DELETE 8
-
- #define BOOL int
-
- /*
- * MS Windows compatible defines
- */
-
- #define MK_CONTROL 0x4
- #define MK_SHIFT 0x2
-
- /*
- * Depending which video mode is being used the colur used will change
- */
-
- /*
- * Default distance of the camera from the origin.
- */
- #define DEFAULT_CAMERA_DISTANCE CREAL(-7.0)
-
-
- /**********************************************************************
- *
- * Type definitions.
- *
- **********************************************************************/
-
- /*
- * This enumerated type tells us what kind of action should be taken
- * on mouse events.
- */
- typedef enum
- {
- MMNoAction,
- MMPanAndZoomCamera,
- MMTiltCamera,
- MMSpinClump,
- MMDragClump,
- MMDragClumpInZ,
- MMPanLight
- } MMMode;
-
- /*
- * This enumerated type tells us what kind of animation action should
- * be taken on timer messages. It is used to allow us to spin clumps
- * for a "momentum" effect.
- */
- typedef enum
- {
- ANoAction,
- ASpinClump
- } AMode;
-
- /**********************************************************************
- *
- * Application global variables.
- *
- **********************************************************************/
-
- /*
- * String for clearing status line
- */
-
- static char sGClear[]=" ";
-
- /*
- * Texts colour
- */
-
- static int nGTextColour;
-
-
- /*
- * Global RenderWare object pointers. In this simple application we
- * make use of only a single scene, camera and light.
- */
- static RwScene *Scene = NULL;
- static RwCamera *Camera = NULL;
- static RwLight *Light = NULL;
-
- /*
- * This variable is used to remember which clump was last picked
- * when spinning or dragging a clump on mouse move events.
- */
- static RwClump *PickedClump = NULL;
-
- /*
- * This matrix is used when spinning a clump, it is stored globally
- * so that it is not necessary to re-build the matrix for each frame of
- * animation.
- */
- static RwMatrix4d *SpinMatrix = NULL;
-
- /*
- * This variable tells us what kind of action to take on a mouse move.
- * The action depends on the object that was picked when the mouse button
- * went down, and on the selection of virtual keys that were depressed at
- * that time. By default no action is taken on mouse move.
- */
- static MMMode MouseMoveMode = MMNoAction;
-
- /*
- * This variable tells us what kind of action to take on timer
- * expiry. It is used to give clumps momentum, i.e. the clump
- * will continue to spin after the user releases the mouse button.
- * By default no animation action is taken.
- */
- static AMode AnimMode = ANoAction;
-
- /*
- * Global variables used to remember the last mouse X and Y coordinates
- * when involved in a pan, zoom, drag or spin.
- */
- static int LastX;
- static int LastY;
-
- /*
- * Current distance the camera is from the origin. This is stored to
- * help us pan and zoom the camera.
- */
- static RwReal CameraDistance = DEFAULT_CAMERA_DISTANCE;
-
- /*
- * Current angle of tilt applied to the camera.
- */
- static RwReal CameraTilt = CREAL(0.0);
-
- /*
- * Current animation frame number. This is incremented each time a
- * frame is drawn on timer expiry. The purpose of this variable is
- * to enable us to periodically (based on the number of frames) call
- * RwOrthoNormalizeMatrix() to correct any errors which have crept
- * into the clump's joint matrix because of the inevitable
- * restrictions on the accuracy of fixed-point numbers. See
- * HandleTimer for more details.
- */
- static int FrameNumber = 0;
-
- /*
- * This flag indicates whether the 3D components of the application
- * have been successfully initialized as yet. It is used to guard
- * the message loop handler functions from being invoked before the
- * 3D components of the application are successfully initialized.
- */
- static BOOL ThreeDInitialized = FALSE;
-
- /* The size of the screen
- */
-
- static int nGScrWidth;
- static int nGScrHeight;
-
- /****************************************************************************
- DosPrintString
-
- On entry : xcord
- : ycord
- : string
- : colour
- On exit :
- */
-
- void DosPrintString(int nX,int nY,char *sString,int nCol)
- {
- RwPrintChar pcPrint;
-
- pcPrint.x = nX;
- pcPrint.y = nY;
- pcPrint.color = nCol;
-
- for (;(*sString);sString++) {
- pcPrint.c = (*sString);
- RwDeviceControl(rwPRINTCHAR,0,&pcPrint,sizeof(RwPrintChar));
- pcPrint.x+=8;
- };
- }
-
-
- /****************************************************************************
- DosTimer
-
- On entry :
- On exit : Timer (in milliseconds)
- */
-
- int DosTimer(void)
- {
- union REGS r;
- int nTime;
-
- r.h.ah=0;
-
- int386(0x1a,&r,&r);
-
- nTime = ((r.w.cx)<<16)|(r.w.dx);
-
- return (nTime*55);
- }
-
- /****************************************************************************
- DosGetKey
-
- Get the ascii key code of any depressed key. (Do not wait for a key press.
- -> return 0 if no key is pressed)
-
- On entry :
- On exit : Key pressed in ascii (or 0 if no key pressed)
- */
-
- int DosGetKey(void)
- {
- union REGPACK rp;
-
- memset(&rp,0,sizeof(rp));
- rp.h.ah = 0x06;
- rp.h.dl = 0xff;
-
- intr(0x21,&rp);
-
- if (!(rp.w.flags & 0x40 )) { /* Check Z flag */
- /* Got key */
-
- if (rp.h.al) {
- return ((int)rp.h.al);
- };
-
- memset(&rp,0,sizeof(rp));
- rp.h.ah = 0x06;
- rp.h.dl = 0xff;
- intr(0x21,&rp);
-
- if (!(rp.w.flags & 0x40)) {
- return ((int)rp.h.al);
- };
-
- return (rp.h.al|0x80);
- };
-
- return 0;
- }
-
- /****************************************************************************
- DosShiftCtrl
-
- Finds the status of the 'Shift/Control' type keys.
-
- On entry :
- On exit : Bit Meaning
- 0 Right Shift
- 1 Left Shift
- 2 Ctrl
- 3 Alt
- 4 Scroll Lock
- 5 Num Lock
- 6 Caps Lock
- 7 Insert on
- */
-
- int DosShiftCtrl(void)
- {
- union REGPACK rp;
-
- memset(&rp,0,sizeof(rp));
-
- rp.h.ah=0x02;
- intr(0x16,&rp);
-
- return ((int)rp.h.al);
- }
-
-
- /**********************************************************************/
-
- /*
- * If using the status bars then show the polgon & vertex count
- of the picked clump in the right status bar */
-
- ShowPickedClumpData(void)
- {
- char string[]=" ";
- if (PickedClump)
- {
- sprintf (string, "%d polygons, %d vertices",
- RwGetClumpNumPolygons(PickedClump),
- RwGetClumpNumVertices(PickedClump));
-
- DosPrintString(0,nGScrHeight-8,string,nGTextColour);
- }
- else
- {
- DosPrintString(0,nGScrHeight-8,string,0);
- };
- }
-
- /**********************************************************************/
-
- /*
- * This function initializes the 3D (i.e. RenderWare) components of the
- * application. This function opens the RenderWare library, creates a
- * camera, a scene, a light and a matrix for spinning. A user-draw may
- * also be created if USERDRAW_LABELS is defined.
- */
- static BOOL
- Init3D(char *sFilename)
- {
- char windowText[128];
- char version[30];
- char buffer[128];
- int param;
- int i;
- RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
- long nError;
-
- /*
- * Attempt to open (and initialize) the RenderWare library.
- */
- if (!RwOpen("DOSMOUSE", &nError))
- {
- printf("Unable to access renderware!!\n");
- switch (nError) {
- case E_RW_DOS_MODE_UNAVAILABLE: {
- printf("The installed VESA card is unable to switch to the resolution");
- printf(" requested.\n");
- printf("Either install a different video adapter or use a ");
- printf("supported video mode.");
- break;
- };
- case E_RW_DOS_NO_VESA_BIOS: {
- printf("A VESA bios is unavailable on this machine.\n");
- printf("Either use a VESA compatible Video Adapter or install a ");
- printf("VESA bios emulation TSR.\n");
- break;
- };
- case E_RW_DOS_INCOMPATIBLE_BIOS: {
- printf("The VESA bios on this machine is not of high enough version ");
- printf("to function\ncorrectly with RenderWare. Use a version 1.0 or");
- printf(" higher VESA bios or TSR.\n");
- break;
- };
- case E_RW_DOS_NO_MOUSE: {
- printf("No Microsoft compatible mouse driver present.\n");
- printf("Install a microsoft compatible mouse driver and try again.\n");
- break;
- };
- default: {
- printf("Unknown Error !!!!!!!!!!!!!!!\n");
- break;
- };
- };
- return FALSE;
- }
-
- /* Set up character set */
-
- RwGetDeviceInfo(rwSCRHEIGHT,&nGScrHeight,sizeof(int));
- RwGetDeviceInfo(rwSCRWIDTH,&nGScrWidth,sizeof(int));
- nGTextColour = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(RwReal[3]));
-
- /*--- Only look for scripts and textures in subdirectories under the current
- one. RWSHAPEPATH need not be set then */
-
- RwSetShapePath(".",rwPRECONCAT);
-
- strcpy(buffer,sFilename);
-
- i = strlen(buffer);
- while((buffer[i] != '\\')&&(i>=0)) {
- i--;
- };
-
-
- if (i>=0) {
- buffer[i+1] = 0;
- strcat(buffer, "TEXTURES");
- RwSetShapePath(buffer, rwPOSTCONCAT);
-
- buffer[i+1] = 0;
- strcat(buffer, "SCRIPTS");
- RwSetShapePath(buffer, rwPOSTCONCAT);
- };
-
- RwSetShapePath("SCRIPTS", rwPRECONCAT);
- RwSetShapePath("TEXTURES", rwPRECONCAT);
-
-
- /*
- * Label the display with information about the version of
- * RenderWare being used. Its rather unlikely that
- * RwGetSystemInfo() will fail so we ignore its return value.
- */
- RwGetSystemInfo(rwVERSIONSTRING, &version,sizeof(version));
- RwGetSystemInfo(rwFIXEDPOINTLIB, ¶m,sizeof(param));
- sprintf(windowText, "RenderWare(tm) V%s %s",
- version, (param ? "Fixed" : "Float"));
- DosPrintString(0,nGScrHeight-16,windowText,nGTextColour);
-
- /*
- * Create the camera which will be used for rendering.
- */
-
- Camera = RwCreateCamera(nGScrWidth,nGScrHeight-24, NULL);
- if (!Camera)
- {
- /*
- * As with RwOpen(), the most common cause for a failure to create
- * a camera is insufficient memory so we will explicitly check for
- * this condition and report it. Otherwise a general error is issued.
- */
- if (RwGetError() == E_RW_NOMEM)
- {
- RwClose();
- printf("Insufficient memory to create the RenderWare(tm) camera\n");
- }
- else
- {
- RwClose();
- printf("Error creating the RenderWare(tm) camera\n");
- }
- exit(-1);
- }
-
-
- /* RwSetCameraProjection(Camera,rwPARALLEL); */
-
-
- RwSetCameraViewport(Camera, 0, 0, nGScrWidth, (nGScrHeight-24));
-
-
-
- /*
- * Set the camera's background color to blue.
- */
- RwSetCameraBackColor(Camera, CREAL(0.3), CREAL(0.0), CREAL(0.0));
-
- /*
- * By default, the camera lies on the X-Z plane and points down Z
- * into the screen. We shall retain the camera's orientation, but move
- * the camera DEFAULT_CAMERA_DISTANCE units down Z away from the screen.
- */
-
- RwTiltCamera(Camera, CameraTilt);
- RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CameraDistance);
-
- /*
- * Another change from previous versions of RenderWare is the amount of
- * prespective generated by the default viewwindow size. When converting
- * applications from previous versions of RenderWare the simple rule is
- * to divide the viewwindow size by five to get the same prespective effect
- * as given under previous versions.
- */
- if (nGScrWidth >= nGScrHeight) {
- RwSetCameraViewwindow(Camera,
- CREAL(1.0),
- RMul(CREAL(1.0),
- RDiv(INT2REAL(nGScrHeight),
- INT2REAL(nGScrWidth))));
- } else {
- RwSetCameraViewwindow(Camera,
- RMul(CREAL(1.0),
- RDiv(INT2REAL(nGScrWidth),
- INT2REAL(nGScrHeight))),
- CREAL(1.0));
- };
-
- /*
- * Create a scene which will contain the clumps to be rendered and the
- * light or lights illuminating those clumps . In this very simple
- * application it would be perfectly acceptable to use the default scene
- * (as returned by RwDefaultScene()) for rendering. However, it is good
- * practice to always create a scene which will be used for your rendering
- * and only use the default scene as a bag for currently unused clumps and
- * lights.
- */
-
- Scene = RwCreateScene();
- if (!Scene)
- {
- RwDestroyCamera(Camera);
- RwClose();
- printf("Error creating the RenderWare(tm) scene\n");
- exit(-1);
- }
-
- /*
- * Our scene will be illuminated by a directional light. The illumination
- * vector of the light is (-1.0, -1.0, -1.0) and its brightness will be 1.0.
- */
-
- Light = RwCreateLight(rwDIRECTIONAL, CREAL(-1.0), CREAL(-1.0), CREAL(-1.0),
- CREAL(1.0));
- if (!Light)
- {
- RwDestroyScene(Scene);
- RwDestroyCamera(Camera);
- RwClose();
- printf("Error creating the RenderWare(tm) light\n");
- exit(-1);
- }
-
- /*
- * Add the new light to our scene.
- */
- RwAddLightToScene(Scene, Light);
-
- /*
- * Create the spin matrix.
- */
- SpinMatrix = RwCreateMatrix();
- if (!SpinMatrix)
- {
- RwDestroyScene(Scene);
- RwDestroyCamera(Camera);
- RwClose();
- printf("Error creating the RenderWare(tm) matrix\n");
- exit(-1);
- }
-
- /*
- * All the 3D components are now successfully initialized, so
- * work can begin...
- */
- ThreeDInitialized = TRUE;
-
- return TRUE;
- }
-
- /**********************************************************************/
-
- /*
- * This function shuts down the 3D (i.e. RenderWare) components of the
- * application in a polite fashion.
- */
-
- static void
- TidyUp3D()
- {
- /*
- * Destroy the spin matrix.
- */
- RwDestroyMatrix(SpinMatrix);
-
- /*
- * Destroy the scene. This will destroy the contents of the scene,
- * i.e. any clumps and lights in that scene. In this case destroying
- * the scene will destroy the light we created in Init3D, and any
- * clumps we have loaded and not already destroyed.
- */
- RwDestroyScene(Scene);
-
- /*
- * Destroy the camera.
- */
- RwDestroyCamera(Camera);
-
- /*
- * Close the library. This will free up any internal resources and
- * textures loaded.
- */
- RwClose();
- }
-
- /**********************************************************************/
-
- /*
- * Attempt to load the file with the given file name as either a clump
- * or a texture (in which case a decal clump is created and returned).
- */
-
- static RwClump *
- LoadClumpOrTexture(char *fileName)
- {
- RwClump *clump;
- RwTexture *texture;
- char buffer[128];
- RwErrorCode eCode;
- char buffer2[128];
-
- DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-24,"Loading File...",nGTextColour);
-
- /*
- * Attempt to load the file as a script file.
- */
- clump = RwReadShape(fileName);
- if (!clump)
- {
- /*
- * The load failed. This could be because of errors in the
- * script file, insufficient memory, or the file containing
- * garbage. We will now examine the error code returned to
- * decide whether there was a script file error (in which case
- * an error will be issued to the user), whether memory was
- * exhausted (a different error is issued to the user), or
- * the file contained garbage (in which case we will attempt
- * to load the file as a texture instead of a script).
- */
- eCode = RwGetError();
-
- switch (eCode)
- {
- case E_RW_NOMEM:
- /*
- * Ran out of memory...
- */
-
- sprintf(buffer, "Insufficient memory : %s",fileName);
- buffer[40]='\0';
- DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
- return NULL;
-
- case E_RW_NOFILE:
- case E_RW_BADOPEN:
- case E_RW_RSPARSE:
- case E_RW_RSREAD:
- case E_RW_READ:
- /*
- * We will (somewhat optimistically) assume that if we
- * had a read or parse error on the stream then the
- * file is not a script file but a texture instead.
- * So attempt to load a texture. Note, as we use
- * RwGetNamedTexture() to get the texture, the texture
- * will not be reloaded if it has been previously loaded
- * into RenderWare.
- */
- texture = RwGetNamedTexture(fileName);
- if (texture)
- {
- /*
- * The file was indeed a texture, so attempt to
- * create a decal clump using this texture.
- */
- clump = RwCreateSprite(texture);
- if (!clump)
- {
- RwGetTextureName(texture,buffer2,sizeof(buffer2));
- sprintf(buffer,
- "Error texture->decal clump %s",buffer2);
- buffer[40]='\0';
- DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
- return NULL;
- }
- }
- else
- {
- /*
- * The texture load failed, issue an error message
- * giving the general nature of the problem.
- */
- switch (RwGetError())
- {
- case E_RW_NOFILE:
- case E_RW_BADOPEN:
- /*
- * Could not open the file...
- */
- sprintf(buffer, "Error opening %s", fileName);
- buffer[40]='\0';
- DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
- return NULL;
-
- case E_RW_NOMEM:
- /*
- * Ran out of memory...
- */
- sprintf(buffer,
- "No mem for texture %s",
- fileName);
- buffer[40]='\0';
- DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
- return NULL;
-
- default:
- /*
- * We will not enumerate all the errors, so simply
- * issue a general failure report.
- */
- sprintf(buffer,
- "Error reading file %s",
- fileName);
- buffer[40]='\0';
- DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
- return NULL;
- }
- }
- break;
-
- default:
- /*
- * On any other error we will assume there is an error in
- * the script file.
- */
- sprintf(buffer,
- "Error in file %s <%i>",fileName,(int)eCode);
- buffer[40]='\0';
-
- DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-24,buffer,nGTextColour);
- return NULL;
- }
- }
-
-
- /*
- * Return the resulting clump.
- */
- DosPrintString(0,nGScrHeight-24,sGClear,nGTextColour);
- return clump;
- }
-
- /**********************************************************************/
-
- /*
- * Parse the names of any .rwx files on the command line, read those
- * files and add them to the scene. This allows DosView to be associated
- * with .rwx files in the file manager and be started automatically when
- * a .rwx file is double-clicked.
- */
- static BOOL
- ReadFromCommandLine(int argc, char *argv[])
- {
- int nCount;
- RwClump *clump;
-
- for (nCount=1;nCount<argc;nCount++) {
- clump = LoadClumpOrTexture(argv[nCount]);
- if (clump) {
- RwAddClumpToScene(Scene, clump);
- };
- };
-
- return 1;
- }
-
- /**********************************************************************/
-
- /*
- * This functions handles the left mouse button going down. Its main
- * job is to determine the kind of action to be taken when the mouse
- * moves, such as spinning a clump, or panning the camera. This involves
- * examining the virtual keys that were depressed when the mouse button
- * went down and attempting to pick a clump under the mouse pointer
- * position.
- */
- static void
- HandleLeftButtonDown(int x, int y, int vKeys)
- {
- RwPickRecord pick;
- int nPos;
- char sBuffer[40];
- int nKey;
- RwClump *clump;
-
- /* Check the area where the click took place */
-
- if (y>(nGScrHeight-16)) {
- /* Its off the bottom of the screen -> enter filename */
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-8,"Filename : @",nGTextColour);
-
- nPos = 0;
- sBuffer[0]='\0';
-
- do {
- nKey = DosGetKey();
-
- if ((nPos>0)&&(nKey==8)) {
- RwDPrintChar((nPos+11)<<3,nGScrHeight-8,'@',nGTextColour);
- RwDPrintChar((nPos+12)<<3,nGScrHeight-8,' ',nGTextColour);
- nPos--;
- sBuffer[nPos]='\0';
- };
-
- if ((nPos<25)&&(nKey>32)&&(nKey<127)) {
- sBuffer[nPos]=nKey;
- nPos++;
- sBuffer[nPos]='\0';
-
- RwDPrintChar((nPos+11)<<3,nGScrHeight-8,nKey,nGTextColour);
- RwDPrintChar((nPos+1+11)<<3,nGScrHeight-8,'@',nGTextColour);
- };
-
- } while (nKey!=13);
-
-
- if (nPos>0) {
- clump = LoadClumpOrTexture(sBuffer);
-
- if (clump) {
- RwAddClumpToScene(Scene, clump);
- };
- };
-
- return;
- };
-
- /*
- * If the left button is depressed anywhere in the client area of the
- * window then the animated spin is cancelled.
- */
- AnimMode = ANoAction;
-
- /*
- * The mouse move action is based on whether an object is picked or
- * not. Therefore, attempt to pick an object in the scene.
- */
- if (RwPickScene(Scene, x, y, Camera, &pick)) {
- switch (pick.type) {
- case rwNAPICKOBJECT:
- /*
- * Clicked on the background, so there is no drag action or
- * picked clump.
- */
- MouseMoveMode = MMNoAction;
- PickedClump = NULL;
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-8,"Stop Clump Rotation",nGTextColour);
- break;
-
- case rwPICKCLUMP:
- /*
- * If a clump was picked and both the shift and control
- * virtual keys were depressed then we will destroy the
- * clump (and hence remove it from the scene).
- */
- if ((vKeys & (MK_CONTROL | MK_SHIFT)) ==
- (MK_CONTROL | MK_SHIFT)) {
- RwDPointerRemove();
-
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-8,"Destroy Clump",nGTextColour);
-
- /*
- * Destroy the clump (and remove it from the scene).
- */
- RwDestroyClump(pick.object.clump.clump);
-
- /*
- * The clump has been destroyed so there is no mouse
- * move action and no picked clump.
- */
- MouseMoveMode = MMNoAction;
- PickedClump = NULL;
- }
- else
- {
- /*
- * A clump was picked, so remember which clump was picked
- * in order that it may be manipulated later when the
- * mouse moves.
- */
- PickedClump = pick.object.clump.clump;
-
- /*
- * Determine the exact nature of the manipulation of
- * the clump on mouse move by examining the virtual key
- * state. If the shift key was depressed, then drag
- * the clump, otherwise, spin it.
- */
- if (vKeys & MK_SHIFT)
- {
- MouseMoveMode = MMDragClump;
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-8,"Drag Clump",nGTextColour);
- }
- else if (vKeys & MK_CONTROL)
- {
- MouseMoveMode = MMDragClumpInZ;
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-8,"Drag Clump in Z",nGTextColour);
- }
- else
- {
- MouseMoveMode = MMSpinClump;
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-8,"Rotate Clump",nGTextColour);
- }
- }
- break;
- }
- }
-
- /*
- * If any form of action is to be taken on mouse move, remember the
- * the current x and y position of the mouse and capture future
- * mouse movement.
- */
- if (MouseMoveMode != MMNoAction)
- {
- LastX = x;
- LastY = y;
- }
-
- RwDPointerRemove();
- ShowPickedClumpData();
- }
-
- /**********************************************************************/
-
- /*
- * This functions handles the right mouse button going down. Its main
- * job is to determine the kind of action to be taken when the mouse
- * moves such as panning the camera.
- */
- static void
- HandleRightButtonDown(int x, int y, int vKeys)
- {
-
- if (vKeys & MK_CONTROL)
- {
- MouseMoveMode = MMPanLight;
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-8,"Pan Light",nGTextColour);
- }
- else if (vKeys & MK_SHIFT)
- {
- MouseMoveMode = MMTiltCamera;
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-8,"Tilt Camera",nGTextColour);
- }
- else
- {
- MouseMoveMode = MMPanAndZoomCamera;
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- DosPrintString(0,nGScrHeight-8,"Pan and Zoom Camera",nGTextColour);
- }
-
- /*
- * If any form of action is to be taken on mouse move, remember the
- * the current x and y position of the mouse and capture future
- * mouse movement.
- */
- if (MouseMoveMode != MMNoAction)
- {
- LastX = x;
- LastY = y;
- }
- }
-
-
- /**********************************************************************/
-
- /*
- * Handle a movement of the mouse. If a previous left or right mouse
- * button down event has set a mouse move mode then this function will
- * take the necessary actions. For example, pan and zooming the camera,
- * panning the light, dragging or spinning a clump etc.
- */
- static void
- HandleMouseMove(int x, int y)
- {
- RwClump *parent;
- RwMatrix4d *tmpMatrix;
- RwMatrix4d *worldToLocal;
- RwV3d up;
- RwV3d right;
- RwV3d at;
- RwReal xDelta;
- RwReal yDelta;
- RwReal xAngle;
- RwReal yAngle;
-
- /*
- * MouseMoveMode tells us what kind of action to perform.
- */
- switch (MouseMoveMode) {
- case MMNoAction:
- break;
-
- case MMPanAndZoomCamera:
- /*
- * We are panning and zooming the camera. Movement of the
- * mouse in the X direction will pan the camera about the
- * origin of world coordinate space, and movement of the mouse
- * in the Y direction will zoom the camera into and out of the
- * the scene.
- */
-
- /*
- * Move the camera back to the origin, as we wish to pan about
- * the origin of the world and not about the origin of the
- * camera.
- */
- RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), -CameraDistance);
-
- /*
- * Undo the tilt as we wish to pan about the world Y axis.
- */
- RwTiltCamera(Camera, -CameraTilt);
-
- /*
- * Pan the camera by mouse X delta degrees.
- */
- RwPanCamera(Camera, INT2REAL(LastX - x));
-
- /*
- * Zoom the camera by changing the distance the camera
- * is from the origin of the world by mouse Y delta divided
- * by 10 units.
- */
- CameraDistance = RAdd(CameraDistance,
- RDiv(INT2REAL(LastY - y), CREAL(10.0)));
-
- /*
- * Redo the tilt.
- */
- RwTiltCamera(Camera, CameraTilt);
-
- /*
- * Move the camera out to its new distance from the world's
- * origin.
- */
- RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CameraDistance);
- break;
-
- case MMTiltCamera:
- /*
- * Move the camera back to the origin, as we wish to tilt about
- * the origin of the world and not about the origin of the
- * camera.
- */
- RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), -CameraDistance);
-
- /*
- * Undo the existing tilt.
- */
- RwTiltCamera(Camera, -CameraTilt);
-
- /*
- * Compute the new angle of tilt.
- */
- CameraTilt = RAdd(CameraTilt, INT2REAL(LastY - y));
-
- /*
- * Apply the new tilt.
- */
- RwTiltCamera(Camera, CameraTilt);
-
- /*
- * Move the camera back out.
- */
- RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CameraDistance);
- break;
-
- case MMSpinClump:
- /*
- * Compute the angles of spin (simply derived from the mouse move deltas).
- */
- yAngle = INT2REAL(x - LastX);
- xAngle = INT2REAL(y - LastY);
-
- /*
- * In DosView, a clump is spun about its own, local coordinate system,
- * origin, rather than the origin of the world coordinate system. There
- * are a number of ways this could be achieved, but the most convenient
- * is to simply apply the rotations to the clump's joint (articulation)
- * transform.
- *
- * A further important point is that the axes of rotation must be the
- * camera's Look Up and Look Right vector rather than simply
- * [CREAL(0.0), CREAL(1.0), CREAL(0.0)] and
- * [CREAL(1.0), CREAL(0.0), CREAL(0.0)]. This ensures that, if the camera
- * has been panned, tilted, revolved or transformed so that it no longer
- * looks down the Z axis, user interaction will still operate correctly,
- * i.e. moving the mouse to the left will spin the clump clockwise etc.
- *
- * Therefore, the first stage is to get the camera's Look Up and
- * Look Right vectors.
- */
- RwGetCameraLookUp(Camera, &up);
- RwGetCameraLookRight(Camera, &right);
-
- /*
- * Unfortunately, rotation about the camera's Look Up and Look Right
- * vectors is complicated if the clump being manipulated is a child
- * clump (i.e. not the root of a clump hierarchy). If this is the
- * case, the camera's vectors have to be transformed into the
- * coordinate space of the parent of the clump being manipulated.
- */
- if ((parent = RwGetClumpParent(PickedClump))) {
- /*
- * Get a handle to a couple of temporary matrices.
- */
- tmpMatrix = RwPushScratchMatrix();
- worldToLocal = RwPushScratchMatrix();
-
- /*
- * Get the parent clump's LTM (which maps local coordinates to
- * world space).
- */
- RwGetClumpLTM(parent, tmpMatrix);
-
- /*
- * Invert it so that it maps world coordinates to the parent's
- * local coordinate space.
- */
- RwInvertMatrix(tmpMatrix, worldToLocal);
-
- /*
- * And transform the camera's vectors into local space.
- */
- RwTransformVector(&up, worldToLocal);
- RwNormalize(&up);
- RwTransformVector(&right, worldToLocal);
- RwNormalize(&right);
-
- /*
- * Discard the temporary matrices.
- */
- RwPopScratchMatrix();
- RwPopScratchMatrix();
- }
-
- /*
- * Apply the rotations.
- */
- RwRotateMatrix(SpinMatrix, up.x, up.y, up.z, yAngle, rwREPLACE);
- RwRotateMatrix(SpinMatrix, right.x, right.y, right.z, xAngle, rwPOSTCONCAT);
-
- /*
- * Apply the resulting, composite transformation to the clump.
- */
- RwTransformClumpJoint(PickedClump, SpinMatrix, rwPOSTCONCAT);
-
- /*
- * As the mouse has moved enable the clump spin.
- */
- AnimMode = ASpinClump;
-
- break;
-
- case MMDragClump:
- RwPushScratchMatrix();
- /*
- * Compute the amount to translate the object by. This is simply
- * derived from the mouse deltas scaled by some arbitrary quantity
- * to prevent objects moving too "quickly".
- */
- xDelta = RDiv(INT2REAL(x - LastX), CREAL(50.0));
- yDelta = RDiv(INT2REAL(LastY - y), CREAL(50.0));
-
- /*
- * In a similar fashion to spinning a clump we must take into account
- * the camera's orientation when dragging a clump. This is done by
- * translating along the camera's look up and look right vectors
- * (scaled appropriately) rather than the clump's local axes.
- */
- RwGetCameraLookRight(Camera, &right);
- RwGetCameraLookUp(Camera, &up);
-
- /*
- * See the previous case for a description of why the following is
- * necessary.
- */
- if ((parent = RwGetClumpParent(PickedClump)))
- {
- tmpMatrix = RwPushScratchMatrix();
- worldToLocal = RwPushScratchMatrix();
- RwGetClumpLTM(parent, tmpMatrix);
- RwInvertMatrix(tmpMatrix, worldToLocal);
- RwTransformVector(&up, worldToLocal);
- RwNormalize(&up);
- RwTransformVector(&right, worldToLocal);
- RwNormalize(&right);
- RwPopScratchMatrix();
- RwPopScratchMatrix();
- }
-
- /*
- * Perform the translations.
- */
- RwTranslateMatrix(RwScratchMatrix(),
- RMul(right.x, xDelta), RMul(right.y, xDelta),
- RMul(right.z, xDelta), rwREPLACE);
- RwTranslateMatrix(RwScratchMatrix(),
- RMul(up.x, yDelta), RMul(up.y, yDelta),
- RMul(up.z, yDelta), rwPOSTCONCAT);
-
- /*
- * Apply the resulting, composite transform to the clump.
- */
- RwTransformClump(PickedClump, RwScratchMatrix(), rwPOSTCONCAT);
-
- RwPopScratchMatrix();
- break;
-
- case MMDragClumpInZ:
- RwPushScratchMatrix();
- /*
- * Compute the amount to translate the object by. This is simply
- * derived from the mouse deltas scaled by some arbitrary quantity
- * to prevent objects moving too "quickly".
- */
- yDelta = RDiv(INT2REAL(LastY - y), CREAL(50.0));
-
- /*
- * In a similar fashion to spinning a clump we must take into account
- * the camera's orientation when dragging a clump. This is done by
- * translating along the camera's Look At vector (scaled appropriately)
- * rather than the clump's local axes.
- */
- RwGetCameraLookAt(Camera, &at);
-
- /*
- * See the case for MMSpinClump: for a description of why the
- * following is necessary.
- */
- if ((parent = RwGetClumpParent(PickedClump)))
- {
- tmpMatrix = RwPushScratchMatrix();
- worldToLocal = RwPushScratchMatrix();
- RwGetClumpLTM(parent, tmpMatrix);
- RwInvertMatrix(tmpMatrix, worldToLocal);
- RwTransformVector(&at, worldToLocal);
- RwNormalize(&at);
- RwPopScratchMatrix();
- RwPopScratchMatrix();
- }
-
- /*
- * Perform the translation.
- */
- RwTranslateMatrix(RwScratchMatrix(),
- RMul(at.x, yDelta), RMul(at.y, yDelta),
- RMul(at.z, yDelta), rwREPLACE);
-
- /*
- * Apply the resulting, composite transform to the clump.
- */
- RwTransformClump(PickedClump, RwScratchMatrix(), rwPOSTCONCAT);
-
- RwPopScratchMatrix();
- break;
-
- case MMPanLight:
- /*
- * We are panning the light about the origin. We will rotate
- * the light about the Y axis for movements of the mouse in
- * X and rotate the light about the X axis for movements of
- * the mouse in Y. In this case we will ignore the effects
- * of camera orientation changes.
- */
- RwPushScratchMatrix();
- /*
- * Replace the CTM with a rotation matrix about Y. The number
- * of degrees of rotation is given by the mouse X delta.
- */
- RwRotateMatrix(RwScratchMatrix(), CREAL(0.0), CREAL(1.0), CREAL(0.0),
- INT2REAL(LastX - x), rwREPLACE);
-
- /*
- * Postconcat another rotation onto the CTM. The new rotation
- * is a rotation about X, the angle being given by the mouse
- * Y delta.
- */
- RwRotateMatrix(RwScratchMatrix(), CREAL(1.0), CREAL(0.0), CREAL(0.0),
- INT2REAL(LastY - y), rwPOSTCONCAT);
-
- /*
- * Transform the light by the resultant rotations.
- */
- RwTransformLight(Light, RwScratchMatrix(),rwPOSTCONCAT);
- RwPopScratchMatrix();
- break;
- }
-
- /*
- * Remember the current X and Y for next time.
- */
- LastX = x;
- LastY = y;
- }
-
- /**********************************************************************/
-
- /*
- * Handle the left mouse button comming back up. The basic action is
- * to turn off mouse move actions and release mouse capture.
- */
-
- static void
- HandleLeftButtonUp(void)
- {
- /*
- * If we were engaged in a mouse move action and the button has come
- * back up, then terminate the action and release mouse capture.
- */
- if (MouseMoveMode != MMNoAction)
- {
- MouseMoveMode = MMNoAction;
- }
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- }
-
- /**********************************************************************/
-
- /*
- * Handle the right mouse button comming back up. The basic action is
- * to turn of mouse move actions and release mouse capture.
- */
- static void
- HandleRightButtonUp(void)
- {
- /*
- * If we were engaged in a mouse move action and the button has come
- * back up, then terminate the action and release mouse capture.
- */
- if (MouseMoveMode != MMNoAction)
- {
- MouseMoveMode = MMNoAction;
- }
- RwDPointerRemove();
- DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
- }
-
- /**********************************************************************/
-
- /*
- * Handle MS Window's timer expiry. This function will perform any
- * animation actions necessary, including spinning clumps and animating
- * textures.
- */
- static void
- HandleTimer(void) {
- /*
- * Determine if there is a clump to spin.
- */
-
-
-
- if (PickedClump && (AnimMode != ANoAction) && (MouseMoveMode == MMNoAction))
- {
- switch (AnimMode) {
- case ASpinClump:
- /*
- * Spin the last clump picked by the last computed spin matrix.
- */
-
-
-
- RwTransformClumpJoint(PickedClump, SpinMatrix, rwPOSTCONCAT);
-
- FrameNumber++;
- if ((FrameNumber & 0x7f) == 0) {
- /*
- * Every 128 frames (a somewhat arbitrary frequency) we call
- * RwOrthoNormalizeMatrix() on the clump's joint matrix to
- * correct any errors which may have crept into it during
- * successive matrix concatenations. This is necessary due
- * to the inevitable accuracy limitations of fixed-point
- * numbers. It is unlikely that this action will be necessary
- * in your own applications unless you perform a very large
- * number of incremental rotation matrix concatenations (as
- * is done here). If this is the case with your application,
- * periodic use of RwOrthoNormalizeMatrix() will ensure
- * that these rounding errors will be eliminated.
- *
- * We call RwOrthoNormalizeMatrix() in the floating-point
- * version of DosView as well, as it is not a particularly
- * expensive operation and the same problems of rounding
- * errors in matrices can occur when using floating-point.
- * Although they are more uncommon.
- */
-
- RwPushScratchMatrix();
-
- RwGetClumpJointMatrix(PickedClump, RwScratchMatrix());
-
- RwOrthoNormalizeMatrix(RwScratchMatrix(), RwScratchMatrix());
-
- RwTransformClumpJoint(PickedClump, RwScratchMatrix(), rwREPLACE);
-
- RwPopScratchMatrix();
-
- }
-
- break;
- }
- }
-
- /*
- * Animate textures. Enumerate over all the textures in the texture
- * dictionary stack calling RwTextureNextFrame() to bump the
- * current frame pointer of each texture. For single frame textures
- * this is a no-op.
- */
-
-
- if (!(FrameNumber&15)) {
- RwForAllNamedTextures(RwTextureNextFrame);
- };
-
-
- /*
- * See the description of HandlePaint() for a description of this common
- * RenderWare cliche for rendering a scene and copying it to the display.
- */
-
- RwBeginCameraUpdate(Camera,NULL);
- RwClearCameraViewport(Camera);
- RwRenderScene(Scene);
- RwEndCameraUpdate(Camera);
-
- RwShowCameraImage(Camera, NULL);
- }
-
-
- /****************************************************************************
- Main
- */
-
- void main(int nArgc,char *saArgv[])
- {
- int nKey;
- int nMouseX,nMouseY,nMouseBut,nOldMouseBut,nOldMouseX,nOldMouseY;
- int nDX,nDY;
- int nChange;
- int nCtrlShift;
-
- if (!Init3D(saArgv[0]))
- {
- exit(-1);
- };
-
- /*
- * Parse any command line parameters.
- */
- if (!ReadFromCommandLine(nArgc, saArgv))
- {
- TidyUp3D();
- exit(-1);
- };
-
- RwDPointerSetPosition(nGScrWidth>>1,nGScrHeight>>1);
-
- RwDPointerDisplay(&nOldMouseX,&nOldMouseY,&nOldMouseBut);
-
- /* Create pointer */
-
- nKey = DosGetKey();
-
- while (nKey!=27) { /* ESC quits */
-
- RwDPointerDisplay(&nMouseX,&nMouseY,&nMouseBut);
-
- nKey = DosGetKey();
-
- nCtrlShift = DosShiftCtrl();
-
- nDX =(nMouseX-nOldMouseX);
- nDY =(nMouseY-nOldMouseY);
-
- nChange = (nMouseBut&(2+8)) | ( (nOldMouseBut&(2+8)) >>1 );
-
- switch (nChange) {
- case 0+0:
- case 2+1:
- case 8+4:
- case 8+2+4+1: {
- /* No change */
- break;
- };
- case 2:
- case 8+2+4: {
-
- /* Left Button Down */
-
- HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
-
-
- break;
- };
- case 8:
- case 8+2+1: {
- /* Right Button Down */
-
-
- HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
-
-
- break;
- };
- case 8+1: {
- /* Right down left Up */
-
-
- HandleLeftButtonUp();
- HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
-
-
- break;
- };
- case 2+4: {
- /* Right up left Down */
-
-
- HandleRightButtonUp();
- HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
-
-
- break;
- };
- case 8+2: {
- /* Left down RIght Down */
-
-
- HandleRightButtonDown(nMouseX,nMouseY,nCtrlShift);
- HandleLeftButtonDown(nMouseX,nMouseY,nCtrlShift);
-
-
- break;
- };
- case 1+4: {
- /* Left up Right Up */
-
-
- HandleRightButtonUp();
- HandleLeftButtonUp();
-
-
- break;
- };
- case 1:
- case 8+4+1: {
- /* Left up */
-
-
- HandleLeftButtonUp();
-
-
- break;
- };
- case 4:
- case 2+4+1: {
- /* Right up */
-
-
- HandleRightButtonUp();
-
-
- break;
- };
- };
-
- if (nDX||nDY) {
- /* Mouse Move */
- HandleMouseMove(nMouseX,nMouseY);
- };
-
- HandleTimer();
-
- nOldMouseX = nMouseX;
- nOldMouseY = nMouseY;
- nOldMouseBut = nMouseBut;
- };
-
-
- /*
- * Tidy up the 3D (RenderWare) components of the application.
- */
-
- TidyUp3D();
-
- exit(0);
- }
-
-