home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Learn 3D Graphics Programming on the PC
/
Learn_3D_Graphics_Programming_on_the_PC_Ferraro.iso
/
rwdos
/
dosrolle.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-15
|
44KB
|
1,604 lines
/**********************************************************************
*
* File : rwroller.c
*
* Abstract : A very simple, sample RenderWare application for
* Microsoft Windows 3.1. 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. will not, under any
* circumstances, be liable for any lost revenue or other damages arising
* from the use of this file.
*
* Copyright (c) 1994 Criterion Software Ltd.
* All Rights Reserved.
*
* RenderWare is a trademark of Canon Inc.
*
**********************************************************************/
/**********************************************************************
*
* Header files.
*
**********************************************************************/
#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"
#include "rolltype.h"
#include "palette.h"
#include "pick.h"
/**********************************************************************
*
* Application constants.
*
**********************************************************************/
/*
* MS Windows compatible defines
*/
#define MK_CONTROL 0x4
#define MK_SHIFT 0x2
/*
* Default distance of the camera from the origin.
*/
#define DEFAULT_CAMERA_DISTANCE CREAL(-7.0)
/**********************************************************************
*
* Forward functions.
*
**********************************************************************/
/**********************************************************************
*
* Type definitions.
*
**********************************************************************/
/*
* The camera's motion mode.
*/
typedef enum
{
cmNONE, /* No camera motion. */
cmRIDE, /* Camera "rides" the rollercoaster. */
cmSPOTTER, /* "Spotter" camera rotates around the rollercoaster car. */
cmTRAIL, /* Camera trails the car on the rollercoaster. */
cmLEAD, /* Camera "leads" the car on the rollercoaster. */
cmELEVATION, /* Camera pans around and zooms into the rollercoaster elevation. */
cmPLAN /* Camera pans around and zooms into the rollercoaster plan. */
} CMMode;
/*
* This enumerated type tells us what kind of action should be taken
* on mouse events.
*/
typedef enum
{
mmNONE, /* No mouse move action. */
mmMOVECAMERA, /* Move the camera on mouse move. */
mmALTMOVECAMERA, /* Alternative camera motion on mouse move. */
mmMOVECONTROL, /* Move a spline control point on mouse move. */
mmMOVELIGHT /* Move the light. */
} MMMode;
/*
* The direction of motion of the viewer on the track.
*/
typedef enum
{
vmLEVEL,
vmCLIMBING,
vmFALLING
} VMMode;
/**********************************************************************
*
* Application global variables.
*
**********************************************************************/
/*
* The global, single camera instance.
*/
static RwCamera *Camera = NULL;
static CMMode CameraMode = cmRIDE;
static RwReal CameraAngle = CREAL(0.0);
/*
* 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 = mmNONE;
/*
* 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;
/*
* Line Clearing string
*/
char sGClear[]=" ";
/*
* Screen size
*/
int nGScrWidth;
int nGScrHeight;
/*
* Default text colour
*/
static int nGTextColour;
/*
* View Display Mode
*/
static int nGDisplayMode=0;
/*
* 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);
/*
* 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 RwBool ThreeDInitialized = FALSE;
/*
* The current rollercoaster.
*/
static RollerCoasterType *CurrentCoaster = NULL;
/*
* The current control point picked (if any).
*/
static int ControlPoint = 0;
/*
* Whether to show the coaster's car or not.
*/
static RwBool ShowCar = TRUE;
static int DrawFPS;
/*
* Name of the palette and backdrop files to load.
*/
#define PALETTEFILENAME "rwroller.pal"
#define BACKDROPFILENAME "mount64.bmp"
/**********************************************************************
*
* Functions.
*
**********************************************************************/
/****************************************************************************
DosTimer
Uses the DOS 18 per sec timer to find time in millisecs.
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);
}
/****************************************************************************
DosShiftCtrl
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);
}
/****************************************************************************
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(pcPrint));
pcPrint.x+=8;
};
}
/****************************************************************************
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;
}
/**********************************************************************/
static RwBool
TrackBackdropToCamera(RwCamera *camera)
{
RwRaster *backdrop;
RwInt32 backdropWidth;
RwInt32 backdropHeight;
RwV3d at;
RwReal angle;
RwInt32 xOffset;
RwInt32 yOffset;
RwInt32 windowWidth;
RwInt32 windowHeight;
backdrop = RwGetCameraBackdrop(camera);
/*
* No-op if the camera has no backdrop.
*/
if (backdrop != NULL)
{
/*
* Get the window and backdrop dimensions.
*/
RwGetCameraViewport(camera, NULL, NULL, &windowWidth, &windowHeight);
backdropWidth = RwGetRasterWidth(backdrop);
backdropHeight = RwGetRasterHeight(backdrop);
/*
* We use the look at vector for determining both
* horizontal and vertical positioning.
*/
RwGetCameraLookAt(camera, &at);
/*
* Compute the horizontal position. This is done
* by compute the camera's angle of rotate about
* the Z axis. The angle is then directly converted
* into a horizontal backdrop offset.
*/
/*
* Compute the angle in the range 0 => PI.
*/
at.y = CREAL(0.0);
RwNormalize(&at);
if (at.z > CREAL(1.0))
at.z = CREAL(1.0);
else if (at.z < CREAL(-1.0))
at.z = CREAL(-1.0);
angle = FL2REAL(acos(REAL2FL(at.z)));
/*
* Get the angle in the range 0 => 2 PI
*/
if (at.x < CREAL(0.0))
angle = RSub(CREAL(M_2PI), angle);
/*
* The backdrop X offset is derived simply from
* the angle computed above.
*/
xOffset = -REAL2INT(RDiv(RMul(angle, INT2REAL(backdropWidth)), CREAL(M_2PI)));
/*
* Compute the vertical position. This is done by getting
* the angle between the look at vector and the Y axis. We
* simply use the dot product (cosine of the angle) multiplied
* by a scale factor to compute the vertical offset.
*/
RwGetCameraLookAt(Camera, &at);
yOffset = REAL2INT(RAdd(INT2REAL(windowHeight / 2), RMul(RMul(at.y, CREAL(1.5)), INT2REAL(windowHeight / 2)))) - (backdropHeight / 2);
RwSetCameraBackdropOffset(Camera, xOffset, 0);
RwSetCameraBackdropViewportRect(Camera, 0, yOffset, windowWidth, backdropHeight);
}
return TRUE;
}
/**********************************************************************/
/*
* Put camera into ride mode.
*/
static void
SwitchToRideView(void)
{
CameraMode = cmRIDE;
SwitchToCoasterRideMode(CurrentCoaster);
/*UpdateMenu(window); */
}
/**********************************************************************/
/*
* Put camera into ride mode.
*/
static void
SwitchToSpotterView(void)
{
CameraMode = cmSPOTTER;
SwitchToCoasterRideMode(CurrentCoaster);
/*UpdateMenu(window);*/
}
/**********************************************************************/
/*
* Put camera into trail mode.
*/
static void
SwitchToTrailView(void)
{
CameraMode = cmTRAIL;
SwitchToCoasterRideMode(CurrentCoaster);
/*UpdateMenu(window); */
}
/**********************************************************************/
/*
* Put camera into lead mode.
*/
static void
SwitchToLeadView(void)
{
CameraMode = cmLEAD;
SwitchToCoasterRideMode(CurrentCoaster);
/*UpdateMenu(window); */
}
/**********************************************************************/
/*
* Put camera into elevation mode.
*/
static void
SwitchToElevationView(void)
{
CameraMode = cmELEVATION;
SwitchToCoasterEditMode(CurrentCoaster);
RwSetCameraPosition(Camera,
CurrentCoaster->elevationPosition.x,
CurrentCoaster->elevationPosition.y,
CurrentCoaster->elevationPosition.z);
RwPointCamera(Camera,
CREAL(0.0),
CurrentCoaster->elevationPosition.y,
CREAL(0.0));
RwSetCameraLookUp(Camera,
CREAL(0.0),
CREAL(1.0),
CREAL(0.0));
TrackBackdropToCamera(Camera);
/*UpdateMenu(window);*/
}
/**********************************************************************/
/*
* Put the camera into plan mode.
*/
static void
SwitchToPlanView(void)
{
CameraMode = cmPLAN;
SwitchToCoasterEditMode(CurrentCoaster);
RwSetCameraPosition(Camera,
CurrentCoaster->planPosition.x,
CurrentCoaster->planPosition.y,
CurrentCoaster->planPosition.z);
/*
* Unsatisfactory hack to get the camera aligned in the
* way we wish. This itself will fail if the camera's is
* looking down the X-axis already - sigh!
*/
RwSetCameraLookUp(Camera,
CREAL(1.0),
CREAL(0.0),
CREAL(0.0));
RwPointCamera(Camera,
CurrentCoaster->planPosition.x,
CREAL(0.0),
CurrentCoaster->planPosition.z);
RwSetCameraLookUp(Camera,
CREAL(0.0),
CREAL(0.0),
CREAL(1.0));
/*UpdateMenu(window); */
}
/**********************************************************************/
static void
SwitchCoaster(RollerCoasterType *coaster)
{
DestroyRollerCoaster(CurrentCoaster);
CurrentCoaster = coaster;
switch (CameraMode)
{
case cmRIDE:
SwitchToRideView();
break;
case cmSPOTTER:
SwitchToSpotterView();
break;
case cmTRAIL:
SwitchToTrailView();
break;
case cmLEAD:
SwitchToLeadView();
break;
case cmELEVATION:
SwitchToElevationView();
break;
case cmPLAN:
SwitchToPlanView();
break;
}
if (ShowCar)
EnableCoasterCar(CurrentCoaster);
else
DisableCoasterCar(CurrentCoaster);
}
/**********************************************************************/
/*
* 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.
*/
static RwBool
Init3D()
{
char version[30];
char buffer[128];
int param;
int i;
RwReal naWhite[]={CREAL(1.0),CREAL(1.0),CREAL(1.0)};
long nError;
char windowText[128];
RwRaster *backdrop;
RwReal naBlack[] = {CREAL(0.0),CREAL(0.0),CREAL(0.0)};
int nBlack;
RwPointerImage piImage;
RollerCoasterType *coaster;
/*
* Attempt to open (and initialize) the RenderWare library.
* Explicitly specifying the MS Windows driver. Previous
* versions of RenderWare required the application instance
* handle to be specified as the device dependent parameter
* of RwOpen(). Version 1.3 of RenderWare has removed this
* requirement and NULL should be passed instead.
*/
/*
* 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;
}
/* load the palette */
CheckAndReadPalette("rwroller.pal");
nGTextColour = RwDeviceControl(rwSCRGETCOLOR,0,naWhite,sizeof(naWhite));
nBlack = RwDeviceControl(rwSCRGETCOLOR,0,naBlack,sizeof(naBlack));
/* Rematch the pointer image */
piImage.image = NULL;
piImage.hotx=0;
piImage.hoty=0;
piImage.w = nBlack;
piImage.h = nGTextColour;
RwDeviceControl(rwPOINTERSETIMAGE,0,&piImage,sizeof(piImage));
/* Set up character set */
RwGetDeviceInfo(rwSCRHEIGHT,&nGScrHeight,sizeof(nGScrHeight));
RwGetDeviceInfo(rwSCRWIDTH,&nGScrWidth,sizeof(nGScrWidth));
/*--- Only look for scripts and textures in subdirectories under the current
one. RWSHAPEPATH need not be set then */
RwSetShapePath(".",rwPRECONCAT);
strcpy(buffer,".");
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, "DosRoller V%s %s",
version, (param ? "Fixed" : "Float"));
DosPrintString(0,nGScrHeight-16,windowText,nGTextColour);
DosPrintString(8*8,nGScrHeight-24,"Load Save New EditPlan",nGTextColour);
DosPrintString(8*32,nGScrHeight-16,"EditSide",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);
}
RwSetCameraViewport(Camera, 0, 0, nGScrWidth, nGScrHeight-24);
/*
* Set the camera's background color to blue.
*/
RwSetCameraBackColor(Camera, CREAL(0.0), CREAL(0.0), CREAL(0.67));
/*
* 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);
RwSetCameraViewwindow(Camera, CREAL(0.8), CREAL(0.8));
/*
Set up the backdrop
*/
backdrop = RwReadRaster(BACKDROPFILENAME, 0L);
if (backdrop != NULL)
RwSetCameraBackdrop(Camera, backdrop);
/*
* Create a new, default rollercoaster.
*/
CurrentCoaster = CreateRollerCoaster();
if (CurrentCoaster == NULL)
{
RwDestroyCamera(Camera);
RwClose();
return FALSE;
}
coaster = ReadRollerCoaster("track4.rrc");
if (coaster != NULL)
{
SwitchCoaster(coaster);
}
SwitchToRideView();
/*
* 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(void)
{
/*
* Destroy the current coaster.
*/
if (CurrentCoaster)
DestroyRollerCoaster(CurrentCoaster);
/*
* Destroy the camera's backdrop (if any). Backdrops are not
* automatically destroyed by RwDestroyCamera() so we must
* manually destroy the backdrop.
*/
if (RwGetCameraBackdrop(Camera))
RwDestroyRaster(RwGetCameraBackdrop(Camera));
/*
* Destroy the camera.
*/
RwDestroyCamera(Camera);
/*
* Close the library. This will free up any internal resources and
* textures loaded.
*/
RwClose();
}
/**********************************************************************/
/*
* Render the scene and copy it to the window and device context
* given. This function encapsulates the very common RenderWare
* for rendering and updating the display.
*/
static void
RenderScene(void)
{
/*
* Setup the current camera and perform all necessary initialization
* before rendering takes place.
*/
RwBeginCameraUpdate(Camera,NULL);
/*
* Clear the areas of the camera's viewport which were damaged
* last time round. If this call is not made, ghost images of
* previous rendering will remain.
*/
RwClearCameraViewport(Camera);
/*
* Re-render the entire scene.
*/
RwRenderScene(CurrentCoaster->scene);
/*
* Perform all necessary housekeeping after rendering is complete.
* After this call, the camera's image buffer will be ready to be
* copied to the display.
*/
RwEndCameraUpdate(Camera);
/*
* Copy the camera's image buffer to the output window. Under
* MS Windows, RenderWare requires both the window handle of the
* output window and a device context for the client area of the
* window. Therefore, a LONG is created which holds both the
* window handle and device context of the output window. This
* LONG is then passed in as the device specific parameter of
* the RwShowCameraImage() call.
*/
RwShowCameraImage(Camera, NULL);
}
/*******************************************************************************
ReadLine
On entry : (OUT) buffer to put string in
On exit :
*/
void ReadLine(char *cpLine)
{
int nPos;
int nKey;
RwDPointerRemove();
DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
DosPrintString(0,nGScrHeight-8,"Filename : @",nGTextColour);
nPos = 0;
cpLine[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--;
cpLine[nPos]='\0';
};
if ((nPos<25)&&(nKey>32)&&(nKey<127)) {
cpLine[nPos]=nKey;
nPos++;
cpLine[nPos]='\0';
RwDPrintChar((nPos+11)<<3,nGScrHeight-8,nKey,nGTextColour);
RwDPrintChar((nPos+1+11)<<3,nGScrHeight-8,'@',nGTextColour);
};
} while (nKey!=13);
DosPrintString(0,nGScrHeight-8,sGClear,nGTextColour);
}
/**********************************************************************/
/*
* 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)
{
int nOption;
char sBuffer[128];
RollerCoasterType *coaster;
if ((y>nGScrHeight-24)&&(y<nGScrHeight-16)) {
nOption = (x>>6);
switch(nOption) {
case 0: {
DisplayModeFlip();
break;
};
case 1: {
/* Load */
ReadLine(sBuffer);
coaster = ReadRollerCoaster(sBuffer);
if (coaster != NULL)
{
SwitchCoaster(coaster);
}
break;
};
case 2: {
/* Save */
ReadLine(sBuffer);
WriteRollerCoaster(CurrentCoaster,sBuffer);
break;
};
case 3: {
/* New */
coaster = CreateRollerCoaster();
if (coaster != NULL)
{
SwitchCoaster(coaster);
};
break;
};
case 4: {
/* EditPlan */
SwitchToPlanView();
break;
};
default: {
break;
};
};
};
if ((y>nGScrHeight-16)&&(y<nGScrHeight-8)) {
SwitchToElevationView();
};
switch (CameraMode)
{
case cmRIDE:
case cmSPOTTER:
case cmTRAIL:
case cmLEAD:
/*
* The left button does nothing when riding the
* coaster.
*/
MouseMoveMode = mmNONE;
break;
case cmELEVATION:
case cmPLAN:
/*
* If a control point is picked, move the control
* point, otherwise, move the camera.
*/
ControlPoint = IsCoasterControlPointPicked(CurrentCoaster, Camera, x, y);
if (ControlPoint == 0)
{
if (vKeys & MK_SHIFT)
MouseMoveMode = mmALTMOVECAMERA;
else
MouseMoveMode = mmMOVECAMERA;
}
else
{
MouseMoveMode = mmMOVECONTROL;
}
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 != mmNONE)
{
LastX = x;
LastY = y;
}
}
/**********************************************************************/
/*
* 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)
{
/* Stop warnings */
vKeys = vKeys;
MouseMoveMode = mmMOVELIGHT;
/*
* 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 != mmNONE)
{
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,int vKeys)
{
RwV3d position;
RwV3d newPos;
/* Stop warnings */
vKeys = vKeys;
/*
* MouseMoveMode tells us what kind of action to perform.
*/
switch (MouseMoveMode)
{
case mmNONE:
break;
case mmMOVECAMERA:
switch (CameraMode)
{
case cmNONE:
case cmRIDE:
case cmSPOTTER:
case cmTRAIL:
case cmLEAD:
break;
case cmELEVATION:
RwPushScratchMatrix();
RwRotateMatrix(RwScratchMatrix(),
CREAL(0.0),
CREAL(1.0),
CREAL(0.0),
RDiv(INT2REAL(LastX - x), CREAL(5.0)),
rwREPLACE);
RwTransformCamera(Camera, RwScratchMatrix(), rwPOSTCONCAT);
RwPopScratchMatrix();
RwVCMoveCamera(Camera,
CREAL(0.0),
CREAL(0.0),
RDiv(INT2REAL(LastY - y), CREAL(50.0)));
RwGetCameraPosition(Camera, &position);
if (position.x < CREAL(-1.5))
position.x = CREAL(-1.5);
if (position.x > CREAL( 1.5))
position.x = CREAL( 1.5);
if (position.z < CREAL(-1.5))
position.z = CREAL(-1.5);
if (position.z > CREAL( 1.5))
position.z = CREAL( 1.5);
RwSetCameraPosition(Camera, position.x, position.y, position.z);
TrackBackdropToCamera(Camera);
break;
case cmPLAN:
RwVCMoveCamera(Camera,
RDiv(INT2REAL(LastX - x), CREAL(50.0)),
RDiv(INT2REAL(y - LastY), CREAL(50.0)),
CREAL(0.0));
RwGetCameraPosition(Camera, &position);
if (position.x < CREAL(-1.0))
position.x = CREAL(-1.0);
if (position.x > CREAL( 1.0))
position.x = CREAL( 1.0);
if (position.z < CREAL(-1.0))
position.z = CREAL(-1.0);
if (position.z > CREAL( 1.0))
position.z = CREAL( 1.0);
RwSetCameraPosition(Camera, position.x, position.y, position.z);
break;
}
break;
case mmALTMOVECAMERA:
switch (CameraMode)
{
case cmNONE:
case cmRIDE:
case cmSPOTTER:
case cmTRAIL:
case cmLEAD:
break;
case cmELEVATION:
RwVCMoveCamera(Camera,
CREAL(0.0),
RDiv(INT2REAL(y - LastY), CREAL(50.0)),
CREAL(0.0));
RwGetCameraPosition(Camera, &position);
if (position.y < DEFAULTGROUNDLEVEL)
position.y = DEFAULTGROUNDLEVEL;
if (position.y > DEFAULTSKYLEVEL)
position.y = DEFAULTSKYLEVEL;
RwSetCameraPosition(Camera, position.x, position.y, position.z);
TrackBackdropToCamera(Camera);
break;
case cmPLAN:
RwVCMoveCamera(Camera,
CREAL(0.0),
CREAL(0.0),
RDiv(INT2REAL(y - LastY), CREAL(50.0)));
RwGetCameraPosition(Camera, &position);
if (position.y < DEFAULTGROUNDLEVEL)
position.y = DEFAULTGROUNDLEVEL;
if (position.y > DEFAULTSKYLEVEL)
position.y = DEFAULTSKYLEVEL;
RwSetCameraPosition(Camera, position.x, position.y, position.z);
break;
}
break;
case mmMOVECONTROL:
RwPushScratchMatrix();
/*
* This function (from pick.c) returns the new position for a clump which lies under
* the given viewport coordinates. This allows as to drag control points exactly
* under the mouse pointer.
*/
GetClumpPositionUnderPointer(COASTERCONTROLPOINT(CurrentCoaster, ControlPoint),
Camera, x, y, &newPos);
RwTranslateMatrix(RwScratchMatrix(), newPos.x, newPos.y, newPos.z, rwREPLACE);
TransformCoasterControlPoint(CurrentCoaster, ControlPoint, RwScratchMatrix());
RwPopScratchMatrix();
break;
case mmMOVELIGHT:
/*
* 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(CurrentCoaster->light, RwScratchMatrix(), rwPOSTCONCAT);
RwPopScratchMatrix();
break;
}
if (MouseMoveMode != mmNONE)
{
/*
* Re-render the scene and copy the results to the display.
*/
RenderScene();
/*
* 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.
*/
switch (MouseMoveMode)
{
case mmNONE:
break;
case mmMOVECAMERA:
case mmALTMOVECAMERA:
MouseMoveMode = mmNONE;
switch (CameraMode)
{
case cmRIDE:
case cmSPOTTER:
case cmTRAIL:
case cmLEAD:
break;
case cmELEVATION:
RwGetCameraPosition(Camera, &CurrentCoaster->elevationPosition);
break;
case cmPLAN:
RwGetCameraPosition(Camera, &CurrentCoaster->planPosition);
break;
}
break;
case mmMOVECONTROL:
MouseMoveMode = mmNONE;
UpdateCoasterClump(CurrentCoaster);
RwInvalidateCameraViewport(Camera);
RenderScene();
break;
}
}
/**********************************************************************/
/*
* 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()
{
/*
* If we were engaged in a mouse move action and the button has come
* back up, then terminate the action and release mouse capture.
*/
MouseMoveMode = mmNONE;
}
/**********************************************************************/
/*
* Handle MS Window's timer expiry. This function will perform any
* animation actions necessary, including spinning clumps and animating
* textures.
*/
static void
OnTimer()
{
RwReal x;
RwReal y;
RwReal z;
if (MouseMoveMode == mmNONE)
{
switch (CameraMode)
{
case cmRIDE:
UpdateViewParameters(CurrentCoaster);
RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
RwSetCameraLookAt(Camera,
CurrentCoaster->tAt.x,
CurrentCoaster->tAt.y,
CurrentCoaster->tAt.z);
x = RAdd(CurrentCoaster->tPosition.x, RMul(CurrentCoaster->tUp.x, CREAL(0.1)));
y = RAdd(CurrentCoaster->tPosition.y, RMul(CurrentCoaster->tUp.y, CREAL(0.1)));
z = RAdd(CurrentCoaster->tPosition.z, RMul(CurrentCoaster->tUp.z, CREAL(0.1)));
RwSetCameraPosition(Camera, x, y, z);
TrackBackdropToCamera(Camera);
UpdateCoasterVelocity(CurrentCoaster);
break;
case cmSPOTTER:
UpdateViewParameters(CurrentCoaster);
RwSetCameraPosition(Camera,
CurrentCoaster->tPosition.x,
CurrentCoaster->tPosition.y,
CurrentCoaster->tPosition.z);
RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
RwSetCameraLookAt(Camera, CREAL(0.0), CREAL(0.0), CREAL(1.0));
RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
RwPanCamera(Camera, CameraAngle);
RwTiltCamera(Camera, CREAL(40.0));
RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CREAL(-0.20));
TrackBackdropToCamera(Camera);
UpdateCoasterVelocity(CurrentCoaster);
CameraAngle = RAdd(CameraAngle, CREAL(5.0));
if (CameraAngle > CREAL(360.0))
CameraAngle = RSub(CameraAngle, CREAL(360.0));
break;
case cmTRAIL:
UpdateViewParameters(CurrentCoaster);
RwSetCameraPosition(Camera,
CurrentCoaster->tPosition.x,
CurrentCoaster->tPosition.y,
CurrentCoaster->tPosition.z);
RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
RwSetCameraLookAt(Camera,
CurrentCoaster->tAt.x,
CurrentCoaster->tAt.y,
CurrentCoaster->tAt.z);
RwSetCameraLookUp(Camera,
CurrentCoaster->tUp.x,
CurrentCoaster->tUp.y,
CurrentCoaster->tUp.z);
RwTiltCamera(Camera, CREAL(45.0));
RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CREAL(-0.15));
TrackBackdropToCamera(Camera);
UpdateCoasterVelocity(CurrentCoaster);
break;
case cmLEAD:
UpdateViewParameters(CurrentCoaster);
RwSetCameraPosition(Camera,
CurrentCoaster->tPosition.x,
CurrentCoaster->tPosition.y,
CurrentCoaster->tPosition.z);
RwSetCameraLookUp(Camera, CREAL(0.0), CREAL(1.0), CREAL(0.0));
RwSetCameraLookAt(Camera,
CurrentCoaster->tAt.x,
CurrentCoaster->tAt.y,
CurrentCoaster->tAt.z);
RwSetCameraLookUp(Camera,
CurrentCoaster->tUp.x,
CurrentCoaster->tUp.y,
CurrentCoaster->tUp.z);
RwPanCamera(Camera, CREAL(180.0));
RwTiltCamera(Camera, CREAL(60.0));
RwVCMoveCamera(Camera, CREAL(0.0), CREAL(0.0), CREAL(-0.15));
TrackBackdropToCamera(Camera);
UpdateCoasterVelocity(CurrentCoaster);
break;
case cmELEVATION:
case cmPLAN:
UpdateViewParameters(CurrentCoaster);
UpdateCoasterVelocity(CurrentCoaster);
break;
}
}
/*
* Re-render the scene and copy the results to the display.
*/
RenderScene();
}
/**********************************************************************/
/***********************************************************************
DisplayModeFlip
On entry :
On exit :
*/
void DisplayModeFlip(void)
{
nGDisplayMode = (nGDisplayMode+1)&3;
RwDPointerRemove();
switch (nGDisplayMode) {
case 0: {
DosPrintString(0,nGScrHeight-24,"Ride ",nGTextColour);
SwitchToRideView();
break;
};
case 1: {
DosPrintString(0,nGScrHeight-24,"Trail ",nGTextColour);
SwitchToTrailView();
break;
};
case 2: {
DosPrintString(0,nGScrHeight-24,"Lead ",nGTextColour);
SwitchToLeadView();
break;
};
case 3: {
DosPrintString(0,nGScrHeight-24,"Spotter ",nGTextColour);
SwitchToSpotterView();
break;
};
default: {
break;
};
};
}
/****************************************************************************
Main
*/
void main(int nArgc,char *saArgv[])
{
int nKey;
int nMouseX,nMouseY,nMouseBut,nOldMouseBut;
int nChange;
int nShiftCtrl=0;
int nDX,nDY;
/* Stop warnings */
nArgc = nArgc;
saArgv = saArgv;
if (!Init3D())
{
exit(-1);
};
/* Create pointer */
RwDPointerDisplay(&LastX,&LastY,&nOldMouseBut);
nKey = DosGetKey();
DrawFPS = 0;
/* Make sure current mode is displayed on the screen */
DisplayModeFlip();
while (nKey!=27) { /* ESC quits */
RwDPointerDisplay(&nMouseX,&nMouseY,&nMouseBut);
/* The other bits */
nDX =(nMouseX-LastX);
nDY =(nMouseY-LastY);
nKey = DosGetKey();
nShiftCtrl = DosShiftCtrl();
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,nShiftCtrl);
break;
};
case 8:
case 8+2+1: {
/* Right Button Down */
HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
break;
};
case 8+1: {
/* Right down left Up */
HandleLeftButtonUp();
HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
break;
};
case 2+4: {
/* Right up left Down */
HandleRightButtonUp();
HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
break;
};
case 8+2: {
/* Left down RIght Down */
HandleRightButtonDown(nMouseX,nMouseY,nShiftCtrl);
HandleLeftButtonDown(nMouseX,nMouseY,nShiftCtrl);
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)) {
HandleMouseMove(nMouseX,nMouseY,nShiftCtrl);
};
OnTimer();
nOldMouseBut = nMouseBut;
};
/*
* Tidy up the 3D (RenderWare) components of the application.
*/
TidyUp3D();
exit(0);
}