home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- *
- * File : pick.c
- *
- * 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 <windows.h>
- #include <rwlib.h>
- #include <rwwin.h>
-
- #include "common.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;
- }
-
- /**********************************************************************/
-