X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2Fcml%2Fmathlib%2Fpicking.h;fp=src%2Fcml%2Fmathlib%2Fpicking.h;h=75d169780e7492d2a88369ee4e6a7f4b9fe11743;hp=0000000000000000000000000000000000000000;hb=6b0a0d0efafe34d48ab344fca3b479553bd4e62c;hpb=85783316365181491a3e3c0c63659972477cebba diff --git a/src/cml/mathlib/picking.h b/src/cml/mathlib/picking.h new file mode 100644 index 0000000..75d1697 --- /dev/null +++ b/src/cml/mathlib/picking.h @@ -0,0 +1,195 @@ +/* -*- C++ -*- ------------------------------------------------------------ + +Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ + +The Configurable Math Library (CML) is distributed under the terms of the +Boost Software License, v1.0 (see cml/LICENSE for details). + + *-----------------------------------------------------------------------*/ +/** @file + * @brief + */ + +#ifndef picking_h +#define picking_h + +#include + +/* Functions for picking with rays, volumes, and drag-enclosed volumes. */ + +namespace cml { + +/* Support function for extracting the near and far depth range values from + * a viewport matrix. + */ + +namespace detail { + +// NOTE: Changed 'near' and 'far' to 'n' and 'f' to work around windows.h +// 'near' and 'far' macros. + +template < class MatT, typename Real > void +depth_range_from_viewport_matrix(const MatT& viewport, Real& n, Real& f) +{ + detail::CheckMatHomogeneous3D(viewport); + + n = viewport.basis_element(3,2); + f = viewport.basis_element(2,2) + n; +} + +} // namespace detail + +/* Make a pick ray given screen coordinates and view, projection, and viewport + * matrices. The origin of the ray lies in the near plane of the frustum; the + * direction vector extends to the far plane if 'normalize' is false, and is + * made unit-length if 'normalize' is true (its default value). + * + * Note that the origin of the ray lies in the near plane rather than + * coinciding with the position of the virtual camera, as the latter gives + * incorrect results when the projection is orthographic. + * + * Note also that the screen y coordinate increases from bottom to top rather + * than top to bottom. If mouse coordinates are returned in window space where + * the y coordinate increases from top to bottom (as is often the case), the + * y value should be recomputed as 'y = - y' before being + * submitted to this function. + */ + +template < class MatT_1, class MatT_2, class MatT_3, typename E, class A > +void make_pick_ray( + E pick_x, + E pick_y, + const MatT_1& view, + const MatT_2& projection, + const MatT_3& viewport, + vector& origin, + vector& direction, + bool normalize = true) +{ + typedef vector vector_type; + typedef typename vector_type::value_type value_type; + + // NOTE: Changed 'near' and 'far' to 'n' and 'f' to work around + // windows.h 'near' and 'far' macros. + value_type n, f; + detail::depth_range_from_viewport_matrix(viewport, n, f); + + origin = + unproject_point( + view,projection,viewport,vector_type(pick_x,pick_y,n) + ); + direction = + unproject_point( + view,projection,viewport,vector_type(pick_x,pick_y,f) + ) - origin; + if (normalize) { + direction.normalize(); + } +} + +/* Make a pick volume given the screen coordinates of the center of the + * picking rect, the width and height of the picking rect, and view and + * projection matrices. + * + * The volume is loaded into the 'planes' array. The planes are of the form + * ax+by+cz+d = 0, and are in the order left, right, bottom, top, near, far. + * + * The z_clip argument should be either z_clip_neg_one or z_clip_zero, and + * should correspond to the near z-clipping range of the projection matrix + * argument. + * + * The 'normalize' argument indicates whether the output planes should be + * normalized; its default value is 'true'. + * + * Note that the screen y coordinate increases from bottom to top rather + * than top to bottom. If mouse coordinates are returned in window space where + * the y coordinate increases from top to bottom (as is often the case), the + * y value should be recomputed as 'y = - y' before being + * submitted to this function. + */ + +template < class MatT_1, class MatT_2, typename Real > +void make_pick_volume( + Real pick_x, + Real pick_y, + Real pick_width, + Real pick_height, + Real viewport_x, + Real viewport_y, + Real viewport_width, + Real viewport_height, + const MatT_1& view, + const MatT_2& projection, + Real planes[6][4], + ZClip z_clip, + bool normalize = true) +{ + // FIXME: Should be promoted type... + typedef matrix< + Real, fixed<4,4>, + typename MatT_1::basis_orient, typename MatT_1::layout > + matrix_type; + + matrix_type pick; + matrix_pick( + pick, pick_x, pick_y, pick_width, pick_height, + viewport_x, viewport_y, viewport_width, viewport_height + ); + cml::extract_frustum_planes( + view,detail::matrix_concat_transforms_4x4(projection,pick), + planes,z_clip,normalize); +} + +/* Make a pick volume given two opposite corners of a rectangle in screen + * space, and view and projection matrices. The corners of the screen rect + * need not be in any particular 'order' with regard to the values of the + * coordinates. + * + * The volume is loaded into the 'planes' array. The planes are of the form + * ax+by+cz+d = 0, and are in the order left, right, bottom, top, near, far. + * + * The z_clip argument should be either z_clip_neg_one or z_clip_zero, and + * should correspond to the near z-clipping range of the projection matrix + * argument. + * + * The 'normalize' argument indicates whether the output planes should be + * normalized; its default value is 'true'. + * + * Note that the screen y coordinate increases from bottom to top rather + * than top to bottom. If mouse coordinates are returned in window space where + * the y coordinate increases from top to bottom (as is often the case), the + * y value should be recomputed as 'y = - y' before being + * submitted to this function. + */ + +template < class MatT_1, class MatT_2, typename Real > +void make_pick_drag_volume( + Real pick_x1, + Real pick_y1, + Real pick_x2, + Real pick_y2, + Real viewport_x, + Real viewport_y, + Real viewport_width, + Real viewport_height, + const MatT_1& view, + const MatT_2& projection, + Real planes[6][4], + ZClip z_clip, + bool normalize = true) +{ + typedef Real value_type; + + make_pick_volume( + (pick_x1+pick_x2)*value_type(.5), + (pick_y1+pick_y2)*value_type(.5), + std::fabs(pick_x2-pick_x1), + std::fabs(pick_y2-pick_y1), + viewport_x, viewport_y, viewport_width, viewport_height, + view, projection, planes, z_clip, normalize + ); +} + +} // namespace cml + +#endif