2022-04-07 18:46:57 +02:00

522 lines
16 KiB
C++

///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1998-2011, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////
#include <PyImathFrustum.h>
#include "PyImathDecorators.h"
#include "PyImathExport.h"
#include <Python.h>
#include <boost/python.hpp>
#include <boost/format.hpp>
#include <PyImath.h>
#include <PyImathMathExc.h>
#include <PyImathVec.h>
#include <Iex.h>
namespace PyImath{
using namespace boost::python;
using namespace IMATH_NAMESPACE;
template <class T> struct FrustumName {static const char *value;};
template <> const char *FrustumName<float>::value = "Frustumf";
template <> const char *FrustumName<double>::value = "Frustumd";
template <class T> struct FrustumTestName {static const char *value;};
template <> const char *FrustumTestName<float>::value = "FrustumTestf";
template <> const char *FrustumTestName<double>::value = "FrustumTestd";
template <class T>
static std::string Frustum_repr(const Frustum<T> &f)
{
std::stringstream stream;
stream << FrustumName<T>::value << "(" << f.nearPlane() << ", " << f.farPlane() << ", "
<< f.left() << ", " << f.right() << ", " << f.top() << ", "
<< f.bottom() << ", " << f.orthographic() << ")";
return stream.str();
}
template <class T>
static void
modifyNearAndFar(Frustum<T> &f, T nearPlane, T farPlane)
{
MATH_EXC_ON;
f.modifyNearAndFar (nearPlane, farPlane);
}
template <class T>
static T
fovx(Frustum<T> &f)
{
MATH_EXC_ON;
return f.fovx();
}
template <class T>
static T
fovy(Frustum<T> &f)
{
MATH_EXC_ON;
return f.fovy();
}
template <class T>
static T
aspect(Frustum<T> &f)
{
MATH_EXC_ON;
return f.aspect();
}
template <class T>
static Matrix44<T>
projectionMatrix(Frustum<T> &f)
{
MATH_EXC_ON;
return f.projectionMatrix();
}
template <class T>
static Frustum<T>
window (Frustum<T> &f, T l, T r, T b, T t)
{
MATH_EXC_ON;
return f.window(l, r, b, t);
}
template <class T>
static Line3<T>
projectScreenToRay (Frustum<T> &f, const Vec2<T> &p)
{
MATH_EXC_ON;
return f.projectScreenToRay(p);
}
template <class T>
static Line3<T>
projectScreenToRayTuple(Frustum<T> &f, const tuple &t)
{
MATH_EXC_ON;
if(t.attr("__len__")() == 2)
{
Vec2<T> point;
point.x = extract<T>(t[0]);
point.y = extract<T>(t[1]);
return f.projectScreenToRay(point);
}
else
THROW(IEX_NAMESPACE::LogicExc, "projectScreenToRay expects tuple of length 2");
}
template <class T>
static Vec2<T>
projectPointToScreen (Frustum<T> &f, const Vec3<T> &p)
{
MATH_EXC_ON;
return f.projectPointToScreen(p);
}
template <class T>
static Vec2<T>
projectPointToScreenTuple(Frustum<T> &f, const tuple &t)
{
MATH_EXC_ON;
if(t.attr("__len__")() == 3)
{
Vec3<T> point;
point.x = extract<T>(t[0]);
point.y = extract<T>(t[1]);
point.z = extract<T>(t[2]);
return f.projectPointToScreen(point);
}
else
THROW(IEX_NAMESPACE::LogicExc, "projectPointToScreen expects tuple of length 3");
}
template <class T>
static Vec2<T>
projectPointToScreenObj(Frustum<T> &f, const object &o)
{
MATH_EXC_ON;
Vec3<T> v;
if (PyImath::V3<T>::convert (o.ptr(), &v))
return f.projectPointToScreen(v);
else
THROW(IEX_NAMESPACE::LogicExc, "projectPointToScreen expects tuple of length 3");
}
template <class T>
static T
ZToDepth(Frustum<T> &f, long z, long min, long max)
{
MATH_EXC_ON;
return f.ZToDepth(z, min, max);
}
template <class T>
static T
normalizedZToDepth(Frustum<T> &f, T z)
{
MATH_EXC_ON;
return f.normalizedZToDepth(z);
}
template <class T>
static long
DepthToZ(Frustum<T> &f, T depth, long min, long max)
{
MATH_EXC_ON;
return f.DepthToZ(depth, min, max);
}
template <class T>
static T
worldRadius(Frustum<T> &f, const Vec3<T> &p, T radius)
{
MATH_EXC_ON;
return f.worldRadius(p, radius);
}
template <class T>
static T
worldRadiusTuple(Frustum<T> &f, const tuple &t, T radius)
{
MATH_EXC_ON;
if(t.attr("__len__")() == 3)
{
Vec3<T> point;
point.x = extract<T>(t[0]);
point.y = extract<T>(t[1]);
point.z = extract<T>(t[2]);
return f.worldRadius(point, radius);
}
else
THROW(IEX_NAMESPACE::LogicExc, "worldRadius expects tuple of length 3");
}
template <class T>
static T
screenRadius(Frustum<T> &f, const Vec3<T> &p, T radius)
{
MATH_EXC_ON;
return f.screenRadius(p, radius);
}
template <class T>
static T
screenRadiusTuple(Frustum<T> &f, const tuple &t, T radius)
{
MATH_EXC_ON;
if(t.attr("__len__")() == 3)
{
Vec3<T> point;
point.x = extract<T>(t[0]);
point.y = extract<T>(t[1]);
point.z = extract<T>(t[2]);
return f.screenRadius(point, radius);
}
else
THROW(IEX_NAMESPACE::LogicExc, "screenRadius expects tuple of length 3");
}
template <class T>
static void
planes1(Frustum<T> &f, Plane3<T> *p)
{
MATH_EXC_ON;
f.planes(p);
}
template <class T>
static void
planes2(Frustum<T> &f, Plane3<T> *p, const Matrix44<T> &m)
{
MATH_EXC_ON;
f.planes(p, m);
}
template <class T>
static tuple
planes3(Frustum<T> &f, const Matrix44<T> &mat)
{
MATH_EXC_ON;
IMATH_NAMESPACE::Plane3<T> p[6];
f.planes(p,mat);
tuple t = make_tuple(p[0],p[1],p[2],p[3],p[4],p[5]);
return t;
}
template <class T>
static tuple
planes4(Frustum<T> &f)
{
MATH_EXC_ON;
IMATH_NAMESPACE::Plane3<T> p[6];
f.planes(p);
tuple t = make_tuple(p[0],p[1],p[2],p[3],p[4],p[5]);
return t;
}
template <class T>
class_<Frustum<T> >
register_Frustum()
{
void (IMATH_NAMESPACE::Frustum<T>::*set1)(T,T,T,T,T,T,bool) = &IMATH_NAMESPACE::Frustum<T>::set;
void (IMATH_NAMESPACE::Frustum<T>::*set2)(T,T,T,T,T) = &IMATH_NAMESPACE::Frustum<T>::set;
const char *name = FrustumName<T>::value;
class_< Frustum<T> > frustum_class(name,name,init<Frustum<T> >("copy construction"));
frustum_class
.def(init<>("Frustum() default construction"))
.def(init<T,T,T,T,T,T,bool>("Frustum(nearPlane,farPlane,left,right,top,bottom,ortho) construction"))
.def(init<T,T,T,T,T>("Frustum(nearPlane,farPlane,fovx,fovy,aspect) construction"))
.def(self == self)
.def(self != self)
.def("__repr__",&Frustum_repr<T>)
.def("set", set1,
"F.set(nearPlane, farPlane, left, right, top, bottom, "
"[ortho])\n"
"F.set(nearPlane, farPlane, fovx, fovy, aspect) "
" -- sets the entire state of "
"frustum F as specified. Only one of "
"fovx or fovy may be non-zero.")
.def("set", set2)
.def("modifyNearAndFar", &modifyNearAndFar<T>,
"F.modifyNearAndFar(nearPlane, farPlane) -- modifies "
"the already-valid frustum F as specified")
.def("setOrthographic", &Frustum<T>::setOrthographic,
"F.setOrthographic(b) -- modifies the "
"already-valid frustum F to be orthographic "
"or not")
.def("nearPlane", &Frustum<T>::nearPlane,
"F.nearPlane() -- returns the coordinate of the "
"near clipping plane of frustum F")
.def("farPlane", &Frustum<T>::farPlane,
"F.farPlane() -- returns the coordinate of the "
"far clipping plane of frustum F")
// The following two functions provide backwards compatibility
// with the previous API for this class.
.def("near", &Frustum<T>::nearPlane,
"F.near() -- returns the coordinate of the "
"near clipping plane of frustum F")
.def("far", &Frustum<T>::farPlane,
"F.far() -- returns the coordinate of the "
"far clipping plane of frustum F")
.def("left", &Frustum<T>::left,
"F.left() -- returns the left coordinate of "
"the near clipping window of frustum F")
.def("right", &Frustum<T>::right,
"F.right() -- returns the right coordinate of "
"the near clipping window of frustum F")
.def("top", &Frustum<T>::top,
"F.top() -- returns the top coordinate of "
"the near clipping window of frustum F")
.def("bottom", &Frustum<T>::bottom,
"F.bottom() -- returns the bottom coordinate "
"of the near clipping window of frustum F")
.def("orthographic", &Frustum<T>::orthographic,
"F.orthographic() -- returns whether frustum "
"F is orthographic or not")
.def("planes", planes1<T>,
"F.planes([M]) -- returns a sequence of 6 "
"Plane3s, the sides of the frustum F "
"(top, right, bottom, left, nearPlane, farPlane), "
"optionally transformed by the matrix M "
"if specified")
.def("planes", planes2<T>)
.def("planes", planes3<T>)
.def("planes", planes4<T>)
.def("fovx", &fovx<T>,
"F.fovx() -- derives and returns the "
"x field of view (in radians) for frustum F")
.def("fovy", &fovy<T>,
"F.fovy() -- derives and returns the "
"y field of view (in radians) for frustum F")
.def("aspect", &aspect<T>,
"F.aspect() -- derives and returns the "
"aspect ratio for frustum F")
.def("projectionMatrix", &projectionMatrix<T>,
"F.projectionMatrix() -- derives and returns "
"the projection matrix for frustum F")
.def("window", &window<T>,
"F.window(l,r,b,t) -- takes a rectangle in "
"the screen space (i.e., -1 <= l <= r <= 1, "
"-1 <= b <= t <= 1) of F and returns a new "
"Frustum whose near clipping-plane window "
"is that rectangle in local space")
.def("projectScreenToRay", &projectScreenToRay<T>,
"F.projectScreenToRay(V) -- returns a Line3 "
"through V, a V2 point in screen space")
.def("projectScreenToRay", &projectScreenToRayTuple<T>)
.def("projectPointToScreen", &projectPointToScreen<T>,
"F.projectPointToScreen(V) -- returns the "
"projection of V3 V into screen space")
.def("projectPointToScreen", &projectPointToScreenTuple<T>)
.def("projectPointToScreen", &projectPointToScreenObj<T>)
.def("ZToDepth", &ZToDepth<T>,
"F.ZToDepth(z, zMin, zMax) -- returns the "
"depth (Z in the local space of the "
"frustum F) corresponding to z (a result of "
"transformation by F's projection matrix) "
"after normalizing z to be between zMin "
"and zMax")
.def("normalizedZToDepth", &normalizedZToDepth<T>,
"F.normalizedZToDepth(z) -- returns the "
"depth (Z in the local space of the "
"frustum F) corresponding to z (a result of "
"transformation by F's projection matrix), "
"which is assumed to have been normalized "
"to [-1, 1]")
.def("DepthToZ", &DepthToZ<T>,
"F.DepthToZ(depth, zMin, zMax) -- converts "
"depth (Z in the local space of the frustum "
"F) to z (a result of transformation by F's "
"projection matrix) which is normalized to "
"[zMin, zMax]")
.def("worldRadius", &worldRadius<T>,
"F.worldRadius(V, r) -- returns the radius "
"in F's local space corresponding to the "
"point V and radius r in screen space")
.def("worldRadius", &worldRadiusTuple<T>)
.def("screenRadius", &screenRadius<T>,
"F.screenRadius(V, r) -- returns the radius "
"in screen space corresponding to "
"the point V and radius r in F's local "
"space")
.def("screenRadius", &screenRadiusTuple<T>)
;
decoratecopy(frustum_class);
return frustum_class;
}
template <class T,class T2>
struct IsVisibleTask : public Task
{
const IMATH_NAMESPACE::FrustumTest<T>& frustumTest;
const PyImath::FixedArray<T2>& points;
PyImath::FixedArray<int>& results;
IsVisibleTask(const IMATH_NAMESPACE::FrustumTest<T>& ft, const PyImath::FixedArray<T2> &p, PyImath::FixedArray<int> &r)
: frustumTest(ft), points(p), results(r) {}
void execute(size_t start, size_t end)
{
for(size_t p = start; p < end; ++p)
results[p] = frustumTest.isVisible(IMATH_NAMESPACE::Vec3<T>(points[p]));
}
};
template <class T,class T2>
PyImath::FixedArray<int>
frustumTest_isVisible(IMATH_NAMESPACE::FrustumTest<T>& ft, const PyImath::FixedArray<T2>& points)
{
size_t numPoints = points.len();
PyImath::FixedArray<int> mask(numPoints);
IsVisibleTask<T,T2> task(ft,points,mask);
dispatchTask(task,numPoints);
return mask;
}
template <class T>
class_<FrustumTest<T> >
register_FrustumTest()
{
const char *name = FrustumTestName<T>::value;
bool (FrustumTest<T>::*isVisibleS)(const Sphere3<T> &) const = &FrustumTest<T>::isVisible;
bool (FrustumTest<T>::*isVisibleB)(const Box<Vec3<T> > &) const = &FrustumTest<T>::isVisible;
bool (FrustumTest<T>::*isVisibleV)(const Vec3<T> &) const = &FrustumTest<T>::isVisible;
bool (FrustumTest<T>::*completelyContainsS)(const Sphere3<T> &) const = &FrustumTest<T>::completelyContains;
bool (FrustumTest<T>::*completelyContainsB)(const Box<Vec3<T> > &) const = &FrustumTest<T>::completelyContains;
class_< FrustumTest<T> > frustumtest_class(name,name,init<const IMATH_NAMESPACE::Frustum<T>&,const IMATH_NAMESPACE::Matrix44<T>&>("create a frustum test object from a frustum and transform"));
frustumtest_class
.def("isVisible",isVisibleS)
.def("isVisible",isVisibleB)
.def("isVisible",isVisibleV)
.def("isVisible",&frustumTest_isVisible<T,IMATH_NAMESPACE::V3f>)
.def("completelyContains",completelyContainsS)
.def("completelyContains",completelyContainsB)
;
decoratecopy(frustumtest_class);
return frustumtest_class;
}
template PYIMATH_EXPORT class_<Frustum<float> > register_Frustum<float>();
template PYIMATH_EXPORT class_<Frustum<double> > register_Frustum<double>();
template PYIMATH_EXPORT class_<FrustumTest<float> > register_FrustumTest<float>();
template PYIMATH_EXPORT class_<FrustumTest<double> > register_FrustumTest<double>();
}