mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-19 10:50:58 +00:00
236 lines
6.8 KiB
C++
236 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 ¢er1, float radius1, const Vec3f ¢er2, 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 ¢er, 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;
|
||
|
}
|