open_toontown_panda3d/panda/src/gobj/perspectiveProjection.cxx

207 lines
7.0 KiB
C++

// Filename: perspectiveProjection.cxx
// Created by: drose (18Feb99)
//
////////////////////////////////////////////////////////////////////
#include "geomLine.h"
#include "perspectiveProjection.h"
#include <boundingHexahedron.h>
TypeHandle PerspectiveProjection::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: PerspectiveProjection::make_copy
// Access: Public, Virtual
// Description: Allocates a new Projection just like this one.
////////////////////////////////////////////////////////////////////
Projection *PerspectiveProjection::
make_copy() const {
return new PerspectiveProjection(*this);
}
////////////////////////////////////////////////////////////////////
// Function: PerspectiveProjection::get_projection_mat
// Access: Public, Virtual
// Description: This computes a transform matrix that performs the
// perspective transform defined by the frustum.
////////////////////////////////////////////////////////////////////
LMatrix4f PerspectiveProjection::
get_projection_mat(CoordinateSystem cs) const {
return _frustum.get_perspective_projection_mat(cs);
}
////////////////////////////////////////////////////////////////////
// Function: PerspectiveProjection::make_geometry
// Access: Public, Virtual
// Description: Creates a GeomLine that describes the shape of the
// frustum for this projection
////////////////////////////////////////////////////////////////////
Geom *PerspectiveProjection::
make_geometry(const Colorf &color,
CoordinateSystem cs) const {
Vertexf rtn, ltn, lbn, rbn;
Vertexf rtf, ltf, lbf, rbf;
// x, y, and z here refer to the right, forward, and up vectors,
// which are not necessarily the x, y, and z axes.
LVector3f x = LVector3f::right(cs);
LVector3f y = LVector3f::forward(cs);
LVector3f z = LVector3f::up(cs);
LPoint3f o = LPoint3f::origin(cs);
Vertexf xl = x * _frustum._l;
Vertexf xr = x * _frustum._r;
Vertexf zt = z * _frustum._t;
Vertexf zb = z * _frustum._b;
Vertexf yn = o + (y * _frustum._fnear);
rtn = yn + zt + xr;
ltn = yn + zt + xl;
lbn = yn + zb + xl;
rbn = yn + zb + xr;
float fs = _frustum._ffar / _frustum._fnear;
Vertexf yf = o + (y * _frustum._ffar);
rtf = yf + ((zt + xr) * fs);
ltf = yf + ((zt + xl) * fs);
lbf = yf + ((zb + xl) * fs);
rbf = yf + ((zb + xr) * fs);
PTA_Vertexf coords(0);
PTA_ushort vindex(0);
PTA_Colorf colors(0);
// We just specify overall color
colors.push_back(color);
coords.push_back(rtn);
coords.push_back(ltn);
coords.push_back(lbn);
coords.push_back(rbn);
coords.push_back(rtf);
coords.push_back(ltf);
coords.push_back(lbf);
coords.push_back(rbf);
coords.push_back(o);
// Draw the near plane
vindex.push_back(0); vindex.push_back(1);
vindex.push_back(1); vindex.push_back(2);
vindex.push_back(2); vindex.push_back(3);
vindex.push_back(3); vindex.push_back(0);
// Draw the far plane
vindex.push_back(4); vindex.push_back(5);
vindex.push_back(5); vindex.push_back(6);
vindex.push_back(6); vindex.push_back(7);
vindex.push_back(7); vindex.push_back(4);
// Draw lines from eye to the corners
vindex.push_back(8); vindex.push_back(4);
vindex.push_back(8); vindex.push_back(5);
vindex.push_back(8); vindex.push_back(6);
vindex.push_back(8); vindex.push_back(7);
GeomLine* gline = new GeomLine;
gline->set_coords(coords, G_PER_VERTEX, vindex);
gline->set_colors(colors, G_OVERALL);
gline->set_num_prims(12);
return gline;
}
////////////////////////////////////////////////////////////////////
// Function: PerspectiveProjection::make_bounds
// Access: Public, Virtual
// Description: Allocates and returns a new BoundingVolume that
// encloses the frustum used for this kind of
// projection, if possible. If a suitable bounding
// volume cannot be created, returns NULL.
////////////////////////////////////////////////////////////////////
BoundingVolume *PerspectiveProjection::
make_bounds(CoordinateSystem cs) const {
return new BoundingHexahedron(_frustum, false, cs);
}
////////////////////////////////////////////////////////////////////
// Function: PerspectiveProjection::extrude
// Access: Public, Virtual
// Description: Given a 2-d point in the range (-1,1) in both
// dimensions, where (0,0) is the center of the
// projection and (-1,-1) is the lower-left corner,
// compute the corresponding vector in space that maps
// to this point, if such a vector can be determined.
// Returns true if the vector is defined (in which case
// origin and direction are set to define the vector),
// or false otherwise.
////////////////////////////////////////////////////////////////////
bool PerspectiveProjection::
extrude(const LPoint2f &point2d, LPoint3f &origin, LVector3f &direction,
CoordinateSystem cs) const {
if (point2d[0] < -1 || point2d[0] > 1 ||
point2d[1] < -1 || point2d[1] > 1) {
// The point is off the near plane.
return false;
}
// Scale the point from (-1,1) to the range of the frustum.
LPoint2f scaled(_frustum._l + 0.5 * (point2d[0] + 1.0) *
(_frustum._r - _frustum._l),
_frustum._b + 0.5 * (point2d[1] + 1.0) *
(_frustum._t - _frustum._b));
LVector3f near_vector =
LVector3f::rfu(scaled[0], _frustum._fnear, scaled[1], cs);
LVector3f far_vector =
near_vector * _frustum._ffar / _frustum._fnear;
origin = LPoint3f::origin(cs) + near_vector;
direction = far_vector - near_vector;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PerspectiveProjection::project
// Access: Public, Virtual
// Description: Given a 3-d point in space, determine the 2-d point
// this maps to, in the range (-1,1) in both dimensions,
// where (0,0) is the center of the projection and
// (-1,-1) is the lower-left corner. Returns true if
// the 3-d point is in front of the projection and
// within the viewing frustum (in which case point2d is
// filled in), or false otherwise.
////////////////////////////////////////////////////////////////////
bool PerspectiveProjection::
project(const LPoint3f &point3d, LPoint2f &point2d,
CoordinateSystem cs) const {
float f = point3d.dot(LVector3f::forward(cs));
if (f < _frustum._fnear || f > _frustum._ffar) {
// The point is outside the near or far clipping planes.
return false;
}
float r = point3d.dot(LVector3f::right(cs));
float u = point3d.dot(LVector3f::up(cs));
LPoint2f scaled(r * _frustum._fnear / f, u * _frustum._fnear / f);
if (scaled[0] < _frustum._l || scaled[0] > _frustum._r ||
scaled[1] < _frustum._b || scaled[1] > _frustum._t) {
// The point is outside of the edge planes.
return false;
}
point2d.set((scaled[0] - _frustum._l) * 2.0 /
(_frustum._r - _frustum._l) - 1.0,
(scaled[1] - _frustum._b) * 2.0 /
(_frustum._t - _frustum._b) - 1.0);
return true;
}