gzdoom/src/r_poly_intersection.cpp
2016-11-12 14:55:14 +01:00

235 lines
6.8 KiB
C++

/*
** Various 3D intersection tests
** Copyright (c) 1997-2015 The UICore Team
**
** This software is provided 'as-is', without any express or implied
** warranty. In no event will the authors be held liable for any damages
** arising from the use of this software.
**
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
**
** 1. The origin of this software must not be misrepresented; you must not
** claim that you wrote the original software. If you use this software
** in a product, an acknowledgment in the product documentation would be
** appreciated but is not required.
** 2. Altered source versions must be plainly marked as such, and must not be
** misrepresented as being the original software.
** 3. This notice may not be removed or altered from any source distribution.
**
*/
#include <stdlib.h>
#include "templates.h"
#include "doomdef.h"
#include "r_poly_intersection.h"
IntersectionTest::Result IntersectionTest::plane_aabb(const Vec4f &plane, const AxisAlignedBoundingBox &aabb)
{
Vec3f center = aabb.center();
Vec3f extents = aabb.extents();
float e = extents.x * std::abs(plane.x) + extents.y * std::abs(plane.y) + extents.z * std::abs(plane.z);
float s = center.x * plane.x + center.y * plane.y + center.z * plane.z + plane.w;
if (s - e > 0)
return inside;
else if (s + e < 0)
return outside;
else
return intersecting;
}
IntersectionTest::Result IntersectionTest::plane_obb(const Vec4f &plane, const OrientedBoundingBox &obb)
{
Vec3f n(plane);
float d = plane.w;
float e = obb.extents.x * std::abs(Vec3f::dot(obb.axis_x, n)) + obb.extents.y * std::abs(Vec3f::dot(obb.axis_y, n)) + obb.extents.z * std::abs(Vec3f::dot(obb.axis_z, n));
float s = Vec3f::dot(obb.center, n) + d;
if (s - e > 0)
return inside;
else if (s + e < 0)
return outside;
else
return intersecting;
}
IntersectionTest::OverlapResult IntersectionTest::sphere(const Vec3f &center1, float radius1, const Vec3f &center2, float radius2)
{
Vec3f h = center1 - center2;
float square_distance = Vec3f::dot(h, h);
float radius_sum = radius1 + radius2;
if (square_distance > radius_sum * radius_sum)
return disjoint;
else
return overlap;
}
IntersectionTest::OverlapResult IntersectionTest::sphere_aabb(const Vec3f &center, float radius, const AxisAlignedBoundingBox &aabb)
{
Vec3f a = aabb.aabb_min - center;
Vec3f b = center - aabb.aabb_max;
a.x = std::max(a.x, 0.0f);
a.y = std::max(a.y, 0.0f);
a.z = std::max(a.z, 0.0f);
b.x = std::max(b.x, 0.0f);
b.y = std::max(b.y, 0.0f);
b.z = std::max(b.z, 0.0f);
Vec3f e = a + b;
float d = Vec3f::dot(e, e);
if (d > radius * radius)
return disjoint;
else
return overlap;
}
IntersectionTest::OverlapResult IntersectionTest::aabb(const AxisAlignedBoundingBox &a, const AxisAlignedBoundingBox &b)
{
if (a.aabb_min.x > b.aabb_max.x || b.aabb_min.x > a.aabb_max.x ||
a.aabb_min.y > b.aabb_max.y || b.aabb_min.y > a.aabb_max.y ||
a.aabb_min.z > b.aabb_max.z || b.aabb_min.z > a.aabb_max.z)
{
return disjoint;
}
else
{
return overlap;
}
}
IntersectionTest::Result IntersectionTest::frustum_aabb(const FrustumPlanes &frustum, const AxisAlignedBoundingBox &box)
{
bool is_intersecting = false;
for (int i = 0; i < 6; i++)
{
Result result = plane_aabb(frustum.planes[i], box);
if (result == outside)
return outside;
else if (result == intersecting)
is_intersecting = true;
break;
}
if (is_intersecting)
return intersecting;
else
return inside;
}
IntersectionTest::Result IntersectionTest::frustum_obb(const FrustumPlanes &frustum, const OrientedBoundingBox &box)
{
bool is_intersecting = false;
for (int i = 0; i < 6; i++)
{
Result result = plane_obb(frustum.planes[i], box);
if (result == outside)
return outside;
else if (result == intersecting)
is_intersecting = true;
}
if (is_intersecting)
return intersecting;
else
return inside;
}
IntersectionTest::OverlapResult IntersectionTest::ray_aabb(const Vec3f &ray_start, const Vec3f &ray_end, const AxisAlignedBoundingBox &aabb)
{
Vec3f c = (ray_start + ray_end) * 0.5f;
Vec3f w = ray_end - c;
Vec3f h = aabb.extents();
c -= aabb.center();
Vec3f v(std::abs(w.x), std::abs(w.y), std::abs(w.z));
if (std::abs(c.x) > v.x + h.x || std::abs(c.y) > v.y + h.y || std::abs(c.z) > v.z + h.z)
return disjoint;
if (std::abs(c.y * w.z - c.z * w.y) > h.y * v.z + h.z * v.y ||
std::abs(c.x * w.z - c.z * w.x) > h.x * v.z + h.z * v.x ||
std::abs(c.x * w.y - c.y * w.x) > h.x * v.y + h.y * v.x)
return disjoint;
return overlap;
}
/////////////////////////////////////////////////////////////////////////////
FrustumPlanes::FrustumPlanes()
{
}
FrustumPlanes::FrustumPlanes(const Mat4f &world_to_projection)
{
planes[0] = near_frustum_plane(world_to_projection);
planes[1] = far_frustum_plane(world_to_projection);
planes[2] = left_frustum_plane(world_to_projection);
planes[3] = right_frustum_plane(world_to_projection);
planes[4] = top_frustum_plane(world_to_projection);
planes[5] = bottom_frustum_plane(world_to_projection);
}
Vec4f FrustumPlanes::left_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] + m.matrix[0 + 0 * 4],
m.matrix[3 + 1 * 4] + m.matrix[0 + 1 * 4],
m.matrix[3 + 2 * 4] + m.matrix[0 + 2 * 4],
m.matrix[3 + 3 * 4] + m.matrix[0 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::right_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] - m.matrix[0 + 0 * 4],
m.matrix[3 + 1 * 4] - m.matrix[0 + 1 * 4],
m.matrix[3 + 2 * 4] - m.matrix[0 + 2 * 4],
m.matrix[3 + 3 * 4] - m.matrix[0 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::top_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] - m.matrix[1 + 0 * 4],
m.matrix[3 + 1 * 4] - m.matrix[1 + 1 * 4],
m.matrix[3 + 2 * 4] - m.matrix[1 + 2 * 4],
m.matrix[3 + 3 * 4] - m.matrix[1 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::bottom_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] + m.matrix[1 + 0 * 4],
m.matrix[3 + 1 * 4] + m.matrix[1 + 1 * 4],
m.matrix[3 + 2 * 4] + m.matrix[1 + 2 * 4],
m.matrix[3 + 3 * 4] + m.matrix[1 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::near_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] + m.matrix[2 + 0 * 4],
m.matrix[3 + 1 * 4] + m.matrix[2 + 1 * 4],
m.matrix[3 + 2 * 4] + m.matrix[2 + 2 * 4],
m.matrix[3 + 3 * 4] + m.matrix[2 + 3 * 4]);
plane /= plane.length3();
return plane;
}
Vec4f FrustumPlanes::far_frustum_plane(const Mat4f &m)
{
Vec4f plane(
m.matrix[3 + 0 * 4] - m.matrix[2 + 0 * 4],
m.matrix[3 + 1 * 4] - m.matrix[2 + 1 * 4],
m.matrix[3 + 2 * 4] - m.matrix[2 + 2 * 4],
m.matrix[3 + 3 * 4] - m.matrix[2 + 3 * 4]);
plane /= plane.length3();
return plane;
}