Files
RP412/MUNGA/BOXSPHR.cpp
T
CydandClaude Opus 4.8 4abbf8879f Initial import of Red Planet v4.10 Win32 source
Imports the current Win32 source for the pod-racing game 'Red Planet',
built on the MUNGA engine and its L4 (Win32/DirectX) platform layer:

- MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend
- RP / RP_L4: Red Planet game logic and Win32 application
- DivLoader, Setup1: asset loader and installer project
- lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies

Removed stale Subversion metadata and added .gitignore/.gitattributes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 07:59:51 -05:00

236 lines
6.2 KiB
C++

#include "munga.h"
#pragma hdrstop
#include "boxsolid.h"
#include "origin.h"
#include "linmtrx.h"
#include "line.h"
//#############################################################################
//############################## BoxedSphere ############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedSphere::BoxedSphere(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(extents, SphereType, material, owner, next_solid)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedSphere::~BoxedSphere()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedSphere::IntersectsBounded(const ExtentBox &extents)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------
// Find the centerpoint and radius of the sphere
//----------------------------------------------
//
Point3D center;
center.x = (minX + maxX) * 0.5f;
center.y = (minY + maxY) * 0.5f;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
//
//--------------------------------------------------------------------------
// Constrain the centerpoint of the sphere to be within the bounded extents.
// Then see if the constrained point is within the radius of the sphere. If
// so, it is an intersection
//--------------------------------------------------------------------------
//
Point3D closest = center;
extents.Constrain(&closest);
closest -= center;
return radius*radius >= closest.LengthSquared();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedSphere::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------
// Find the centerpoint and radius of the sphere
//----------------------------------------------
//
Point3D center;
center.x = (minX + maxX) * 0.5f;
center.y = (minY + maxY) * 0.5f;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
//
//-------------------------------------------------------------------------
// translate the test point into the sphere's frame of reference and see if
// it is close enough
//-------------------------------------------------------------------------
//
center -= point;
return radius*radius >= center.LengthSquared();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedSphere::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------
// Find the centerpoint and radius of the sphere
//----------------------------------------------
//
Point3D center;
center.x = (minX + maxX) * 0.5f;
center.y = (minY + maxY) * 0.5f;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
//
//-----------------------------------------------------------------------
// Convert the point to the coordinates of the sphere, putting the center
// point of the sphere at the origin. Note that we are subtracting the
// point from the center point as opposed to the normal way. This will
// result in both X and Y being negated, but since we are squaring them,
// this will not matter
//-----------------------------------------------------------------------
//
Scalar x = center.x - point.x;
Scalar z = center.z - point.z;
Scalar h = radius*radius - x*x - z*z;
if (h < SMALL)
{
return -1.0f;
}
//
//-------------------------------------------------------------------
// If the point is in the XZ shadow of the sphere, then the height is
// determined by the height of the sphere at that point
//-------------------------------------------------------------------
//
Scalar height = point.y - (center.y + Sqrt(h));
return Abs(height);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedSphere::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Check(this);
Check(line);
Verify(enters <= leaves);
Verify(leaves >= 0.0f);
//
//----------------------------------------------
// Find the centerpoint and radius of the sphere
//----------------------------------------------
//
Point3D center;
center.x = (minX + maxX) * 0.5f;
center.y = (minY + maxY) * 0.5f;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
//
//-------------------------------------------------------------------------
// Find the point of closest approach to the center of the sphere, and make
// sure that it is within the boundaries of the sphere
//-------------------------------------------------------------------------
//
Scalar midlen = line->LengthToClosestPointTo(center);
Point3D closest;
line->Project(midlen, &closest);
closest -= center;
Scalar v = radius*radius - closest.LengthSquared();
if (v < 0.0f)
{
return False;
}
//
//---------------------------------------------------------------------
// Find the closest possible length of ray traversal before hitting the
// sphere
//---------------------------------------------------------------------
//
v = Sqrt(v);
Scalar enter = midlen - v;
if (enter > enters)
{
enters = enter;
}
Scalar leave = midlen + v;
if (leave < leaves)
{
leaves = leave;
}
if (enters > leaves || enters > line->length || leaves < 0.0f)
{
return False;
}
line->length = Max(enters, 0.0f);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedSphere::TestInstance() const
{
return solidType == SphereType;
}