home *** CD-ROM | disk | FTP | other *** search
- //*********************************************************************
- //
- // File : pick.cpp
- //
- // Abstract : The implementation of some enhanced picking functionality
- // which use ray casting to determine the exact position
- // of the projection of a viewport position onto an
- // arbitrary plane. These functions can be used to drag
- // objects directly under the mouse cursor.
- //
- // 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, 1995 Criterion Software Ltd.
- // All Rights Reserved.
- //
- // RenderWare is a trademark of Canon Inc.
- //
- //*********************************************************************
-
- //*********************************************************************
- //
- // Header files.
- //
- //*********************************************************************
-
- #include <stdafx.h>
-
- #include <rwlib.h>
- #include <rwwin.h>
-
- #include "pick.h"
-
- //*********************************************************************
- //
- // Functions.
- //
- //*********************************************************************
-
- //*********************************************************************
-
- // Return t at the point of interestion of the given ray and plane.
- // The plane is defined by a point on the plane (p) and a nornal to the
- // plane (n). Returns TRUE if the ray and plane intersect and FALSE if
- // the ray and plane are parallel.
- RwBool
- IntersectRayAndPlane(RwRay *ray, RwV3d *n, RwV3d *p, RwReal *t)
- {
- RwReal div;
-
- div = ::RwDotProduct(&ray->v, n);
- if (div == CREAL(0.0))
- {
- // The the ray is parallel to the plane so there is no
- // intersection.
- return FALSE;
- }
- else
- {
- // Math. voodoo to compute the parameter along the ray of the point
- // of intersection.
- *t = -RDiv(RAdd(-::RwDotProduct(n, p), ::RwDotProduct(&ray->p, n)), div);
- return TRUE;
- }
- }
-
- //*********************************************************************
-
- // Given a camera and a viewport position spawn a ray into world space.
- // NOTE: This function does not take into account camera offsets.
- RwRay *
- SpawnRay(RwCamera *camera, RwInt32 x, RwInt32 y, RwRay *ray)
- {
- RwInt32 vpw;
- RwInt32 vph;
- RwReal vww;
- RwReal vwh;
- RwReal vwx;
- RwReal vwy;
-
- // Convert the viewport position to a viewwindow position.
- ::RwGetCameraViewport(camera, NULL, NULL, &vpw, &vph);
- ::RwGetCameraViewwindow(camera, &vww, &vwh);
- vwx = RSub(RDiv(RMul(INT2REAL(x), vww), INT2REAL(vpw)), RDiv(vww, CREAL(2.0)));
- vwy = RSub(RDiv(RMul(INT2REAL((vph - 1) - y), vwh), INT2REAL(vph)), RDiv(vwh, CREAL(2.0)));
-
- // Initalize the ray in camera space.
- ray->p.x = CREAL(0.0);
- ray->p.y = CREAL(0.0);
- ray->p.z = CREAL(0.0);
- ray->v.x = vwx;
- ray->v.y = vwy;
- ray->v.z = CREAL(0.5);
-
- // Transform the ray into world space.
- ::RwPushScratchMatrix();
- ::RwGetCameraLTM(camera, ::RwScratchMatrix());
- // The camera's positive z points into the screen. For the
- // world, positive z points out of the screen. We need to handle
- // this difference in "handedness" by flipping the x axis. A quick
- // way of doing this is to scale the x axis by -1.
- ::RwScaleMatrix(::RwScratchMatrix(),
- CREAL(-1.0), CREAL(1.0), CREAL(1.0), rwPRECONCAT);
- ::RwTransformVector(&ray->v, ::RwScratchMatrix());
- ::RwTransformPoint(&ray->p, ::RwScratchMatrix());
- ::RwPopScratchMatrix();
-
- return ray;
- }
-
- //*********************************************************************
-
- // Compute the position (in world coordinates) of the given clump under
- // the given (x, y) position in the viewport of the given camera. The
- // clump will keep a constant orientation and distance with respect to
- // the camera, i.e., this function can be used to drag the clump around
- // on the plane parallel to the camera on which the clump lies.
- RwV3d *
- GetClumpPositionUnderPointer(RwClump *clump, RwCamera *camera,
- RwInt32 x, RwInt32 y, RwV3d *pos)
- {
- RwV3d n;
- RwV3d p;
- RwRay ray;
- RwReal t;
-
- // Compute the parameters of the plane on which the clump lies. The
- // plane normal is the negative camera look at vector and the point
- // on the plane is given by the clump's origin.
- ::RwGetCameraLookAt(camera, &n);
- n.x = -n.x;
- n.y = -n.y;
- n.z = -n.z;
- ::RwGetClumpOrigin(clump, &p);
-
- // Spawn a ray from the picked position.
- ::SpawnRay(camera, x, y, &ray);
-
- // Compute the parameter along the ray of the point of intersection.
- // NOTE: This is a special case in that we know the plane is
- // perpindicular to the ray so we know there must be an intersection.
- ::IntersectRayAndPlane(&ray, &n, &p, &t);
-
- // Convert the parameter to an actual world position.
- ::RwScaleVector(&ray.v, t, pos);
- ::RwAddVector(&ray.p, pos, pos);
-
- return pos;
- }
-
- //*********************************************************************
-