This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/WWMath/aabox.h

679 lines
39 KiB
C++

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWMath *
* *
* $Archive:: /Commando/Code/wwmath/aabox.h $*
* *
* Author:: Greg_h *
* *
* $Modtime:: 5/08/01 6:35p $*
* *
* $Revision:: 30 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* AABoxClass::Transform -- transform an aabox *
* AABoxClass::Translate -- transform an aabox *
* AABoxClass::Init -- create a box which bounds the given points *
* AABoxClass::Init -- initialize from a min-max form of a box *
* AABoxClass::Init_Min_Max -- init the box from a min and max vector *
* AABoxClass::Add_Point -- expand the box to contain the given point *
* AABoxClass::Project_To_Axis -- compute projection onto the given axis *
* AABoxClass::Intersects -- test for intersection with another static aabox *
* AABoxClass::Add_Box -- expand this box to enclose the passed box *
* AABoxClass::Add_Box -- Expand this box to enclose the passed box *
* MinMaxAABoxClass::Init -- init the box from an array of points *
* MinMaxAABoxClass::Init -- initializes this box from a center-extent box *
* MinMaxAABoxClass::Add_Point -- updates this box so it encloses the given point *
* MinMaxAABoxClass::Add_Box -- update this box to enclose the given box *
* MinMaxAABoxClass::Add_Box -- Updates this box to enclose the specified box *
* MinMaxAABoxClass::Transform -- Updates this box to enclose its transformed version *
* MinMaxAABoxClass::Translate -- translates the box *
* AABoxClass::Init -- Init from a line segment *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if defined(_MSC_VER)
#pragma once
#endif
#ifndef AABOX_H
#define AABOX_H
#include "always.h"
#include "matrix3d.h"
#include "lineseg.h"
#include "colmath.h"
class AABoxClass;
class MinMaxAABoxClass;
class OBBoxClass;
class TriClass;
class PlaneClass;
struct CastResultStruct;
/*
** AABoxClass
**
** Axis-Aligned Boxes. I've coded these similar to the OrientedBoxClass only
** without a rotation matrix. A similar algorithm is used to test the box
** for intersection.
*/
class AABoxClass
{
public:
WWINLINE AABoxClass(void) { }
WWINLINE AABoxClass(const Vector3 & center,const Vector3 & extent) :
Center(center),
Extent(extent)
{ }
AABoxClass(const MinMaxAABoxClass & minmaxbox) { Init(minmaxbox); }
AABoxClass(Vector3 * points,int num) { Init(points,num); }
bool operator== (const AABoxClass &src);
bool operator!= (const AABoxClass &src);
WWINLINE void Init(const Vector3& center,const Vector3 & extent) { Center = center; Extent = extent; }
WWINLINE void Init(Vector3 * points,int num);
WWINLINE void Init(const MinMaxAABoxClass & minmaxbox);
void Init(const LineSegClass & line);
void Init_Min_Max(const Vector3 & min,const Vector3 & max);
void Init_Random(float min_center = -1.0f,float max_center = 1.0f,float min_extent = 0.5f,float max_extent = 1.0f);
void Add_Point(const Vector3 & point);
void Add_Box(const AABoxClass & b);
void Add_Box(const MinMaxAABoxClass & b);
float Project_To_Axis(const Vector3 & axis) const;
void Transform(const Matrix3D & tm);
void Translate(const Vector3 & pos);
WWINLINE float Volume(void) const { return 2.0*Extent.X * 2.0*Extent.Y * 2.0*Extent.Z; }
WWINLINE bool Contains(const Vector3 & point) const;
WWINLINE bool Contains(const AABoxClass & other_box) const;
WWINLINE bool Contains(const MinMaxAABoxClass & other_box) const;
static void Transform(const Matrix3D & tm,const AABoxClass & in,AABoxClass * out);
Vector3 Center; // world space center
Vector3 Extent; // size of the box in the three directions
};
/*
** MinMaxAABoxClass
** This is another form of an AABox. It can be faster to build one of these
** and then convert it into a center-extent AABox in some cases. Its purpose
** is basically that.
*/
class MinMaxAABoxClass
{
public:
WWINLINE MinMaxAABoxClass(void) { }
WWINLINE MinMaxAABoxClass(const Vector3 & min_corner,const Vector3 & max_corner) :
MinCorner(min_corner),
MaxCorner(max_corner)
{
}
WWINLINE MinMaxAABoxClass(Vector3 * points,int num) { Init(points,num); }
WWINLINE MinMaxAABoxClass(const AABoxClass & that) { Init(that); }
WWINLINE void Init(Vector3 * points,int num);
WWINLINE void Init(const AABoxClass & box);
void Init_Empty(void);
void Add_Point(const Vector3 & point);
void Add_Box(const MinMaxAABoxClass & box);
void Add_Box(const AABoxClass & box);
void Add_Box(const Vector3 & min_corner,const Vector3 & max_corner);
void Transform(const Matrix3D & tm);
void Translate(const Vector3 & pos);
WWINLINE float Volume(void) const { Vector3 size = MaxCorner - MinCorner; return size.X*size.Y*size.Z; }
Vector3 MinCorner;
Vector3 MaxCorner;
};
/***********************************************************************************************
* AABoxClass::Transform -- transform an aabox *
* *
* Note that this function expands the box to enclose its transformed form. *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void AABoxClass::Transform(const Matrix3D & tm)
{
Vector3 oldcenter = Center;
Vector3 oldextent = Extent;
tm.Transform_Center_Extent_AABox(oldcenter,oldextent,&Center,&Extent);
}
/***********************************************************************************************
* AABoxClass::Translate -- translate an aabox *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void AABoxClass::Translate(const Vector3 & trans)
{
Center += trans;
}
/***********************************************************************************************
* AABoxClass::operator== -- Comparison operator *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 6/21/00 PDS : Created. *
*=============================================================================================*/
WWINLINE bool AABoxClass::operator== (const AABoxClass &src)
{
return (Center == src.Center) && (Extent == src.Extent);
}
/***********************************************************************************************
* AABoxClass::operator!= -- Comparison operator *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 6/21/00 PDS : Created. *
*=============================================================================================*/
WWINLINE bool AABoxClass::operator!= (const AABoxClass &src)
{
return (Center != src.Center) || (Extent != src.Extent);
}
/***********************************************************************************************
* AABoxClass::Init -- create a box which bounds the given points *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void AABoxClass::Init(Vector3 * points,int num)
{
Vector3 Min = points[0];
Vector3 Max = points[0];
for (int i=1; i<num; i++) {
if (Min.X > points[i].X) Min.X = points[i].X;
if (Min.Y > points[i].Y) Min.Y = points[i].Y;
if (Min.Z > points[i].Z) Min.Z = points[i].Z;
if (Max.X < points[i].X) Max.X = points[i].X;
if (Max.Y < points[i].Y) Max.Y = points[i].Y;
if (Max.Z < points[i].Z) Max.Z = points[i].Z;
}
Center = (Max + Min) * 0.5f;
Extent = (Max - Min) * 0.5f;
}
/***********************************************************************************************
* AABoxClass::Init -- initialize from a min-max form of a box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void AABoxClass::Init(const MinMaxAABoxClass & mmbox)
{
Center = (mmbox.MaxCorner + mmbox.MinCorner) * 0.5f;
Extent = (mmbox.MaxCorner - mmbox.MinCorner) * 0.5f;
}
/***********************************************************************************************
* AABoxClass::Init -- Init from a line segment *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 4/27/2000 gth : Created. *
*=============================================================================================*/
WWINLINE void AABoxClass::Init(const LineSegClass & line)
{
Vector3 min_corner = line.Get_P0();
Vector3 max_corner = line.Get_P0();
if (min_corner.X > line.Get_P1().X) min_corner.X = line.Get_P1().X;
if (min_corner.Y > line.Get_P1().Y) min_corner.Y = line.Get_P1().Y;
if (min_corner.Z > line.Get_P1().Z) min_corner.Z = line.Get_P1().Z;
if (max_corner.X < line.Get_P1().X) max_corner.X = line.Get_P1().X;
if (max_corner.Y < line.Get_P1().Y) max_corner.Y = line.Get_P1().Y;
if (max_corner.Z < line.Get_P1().Z) max_corner.Z = line.Get_P1().Z;
Center = (max_corner + min_corner) * 0.5f;
Extent = (max_corner - min_corner) * 0.5f;
}
/***********************************************************************************************
* AABoxClass::Init_Min_Max -- init the box from a min and max vector *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 4/9/99 GTH : Created. *
*=============================================================================================*/
WWINLINE void AABoxClass::Init_Min_Max(const Vector3 & min,const Vector3 & max)
{
Center = (max + min) * 0.5f;
Extent = (max - min) * 0.5f;
}
/***********************************************************************************************
* AABoxClass::Add_Point -- expand the box to contain the given point *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void AABoxClass::Add_Point(const Vector3 & point)
{
Vector3 Min = Center - Extent;
Vector3 Max = Center + Extent;
if (Min.X > point.X) Min.X = point.X;
if (Min.Y > point.Y) Min.Y = point.Y;
if (Min.Z > point.Z) Min.Z = point.Z;
if (Max.X < point.X) Max.X = point.X;
if (Max.Y < point.Y) Max.Y = point.Y;
if (Max.Z < point.Z) Max.Z = point.Z;
Center = (Max + Min) / 2.0f;
Extent = (Max - Min) / 2.0f;
}
/***********************************************************************************************
* AABoxClass::Add_Box -- expand this box to enclose the passed box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
* 9/29/2000 gth : Ok to add boxes with zero extent *
*=============================================================================================*/
WWINLINE void AABoxClass::Add_Box(const AABoxClass & b)
{
Vector3 newmin = Center - Extent;
Vector3 newmax = Center + Extent;
newmin.Update_Min(b.Center - b.Extent);
newmax.Update_Max(b.Center + b.Extent);
Center = (newmax + newmin) * 0.5f;
Extent = (newmax - newmin) * 0.5f;
}
/***********************************************************************************************
* AABoxClass::Add_Box -- Expand this box to enclose the passed box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
* 9/29/2000 gth : Ok to add boxes with zero extent *
*=============================================================================================*/
WWINLINE void AABoxClass::Add_Box(const MinMaxAABoxClass & b)
{
Vector3 newmin = Center - Extent;
Vector3 newmax = Center + Extent;
newmin.Update_Min(b.MinCorner);
newmax.Update_Max(b.MaxCorner);
Center = (newmax + newmin) * 0.5f;
Extent = (newmax - newmin) * 0.5f;
}
/***********************************************************************************************
* AABoxClass::Project_To_Axis -- compute projection onto the given axis *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 2/24/98 GTH : Created. *
*=============================================================================================*/
WWINLINE float AABoxClass::Project_To_Axis(const Vector3 & axis) const
{
float x = Extent[0] * axis[0];
float y = Extent[1] * axis[1];
float z = Extent[2] * axis[2];
// projection is the sum of the absolute values of the projections of the three extents
return (WWMath::Fabs(x) + WWMath::Fabs(y) + WWMath::Fabs(z));
}
/***********************************************************************************************
* AABoxClass::Contains -- Test whether this box contains the given box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 9/2/98 GTH : Created. *
*=============================================================================================*/
WWINLINE bool AABoxClass::Contains(const AABoxClass & other_box) const
{
return CollisionMath::Overlap_Test(*this,other_box) == CollisionMath::INSIDE;
}
/***********************************************************************************************
* AABoxClass::Contains -- Test whether this box contains the given box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 9/2/98 GTH : Created. *
*=============================================================================================*/
WWINLINE bool AABoxClass::Contains(const MinMaxAABoxClass & other_box) const
{
Vector3 bmin = Center - Extent;
Vector3 bmax = Center + Extent;
if (other_box.MinCorner.X < bmin.X) return false;
if (other_box.MinCorner.Y < bmin.Y) return false;
if (other_box.MinCorner.Z < bmin.Z) return false;
if (other_box.MaxCorner.X > bmax.X) return false;
if (other_box.MaxCorner.Y > bmax.Y) return false;
if (other_box.MaxCorner.Z > bmax.Z) return false;
return true;
}
/***********************************************************************************************
* AABoxClass::Contains -- test whether this box contains the given point *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 9/2/98 GTH : Created. *
*=============================================================================================*/
WWINLINE bool AABoxClass::Contains(const Vector3 & point) const
{
return CollisionMath::Overlap_Test(*this,point) == CollisionMath::INSIDE;
}
/***********************************************************************************************
* MinMaxAABoxClass::Init -- init the box from an array of points *
* *
* Makes a box which encloses the given array of points *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void MinMaxAABoxClass::Init(Vector3 * points,int num)
{
assert(num > 0);
assert(points != NULL);
MinCorner = points[0];
MaxCorner = points[0];
for (int i=0; i<num; i++) {
MinCorner.Update_Min(points[i]);
MaxCorner.Update_Max(points[i]);
}
}
/***********************************************************************************************
* MinMaxAABoxClass::Init -- initializes this box from a center-extent box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void MinMaxAABoxClass::Init(const AABoxClass & box)
{
MinCorner = box.Center - box.Extent;
MaxCorner = box.Center + box.Extent;
}
/***********************************************************************************************
* MinMaxAABoxClass::Add_Point -- updates this box so it encloses the given point *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void MinMaxAABoxClass::Add_Point(const Vector3 & point)
{
MinCorner.Update_Min(point);
MaxCorner.Update_Max(point);
}
/***********************************************************************************************
* MinMaxAABoxClass::Add_Box -- update this box to enclose the given box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void MinMaxAABoxClass::Add_Box(const MinMaxAABoxClass & box)
{
if (box.MinCorner == box.MaxCorner) return;
MinCorner.Update_Min(box.MinCorner);
MaxCorner.Update_Max(box.MaxCorner);
}
/***********************************************************************************************
* MinMaxAABoxClass::Add_Box -- update this box to enclose the given box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void MinMaxAABoxClass::Add_Box(const AABoxClass & box)
{
if (box.Extent == Vector3(0.0f, 0.0f, 0.0f)) return;
MinCorner.Update_Min(box.Center - box.Extent);
MaxCorner.Update_Max(box.Center + box.Extent);
}
/***********************************************************************************************
* MinMaxAABoxClass::Add_Box -- Updates this box to enclose the specified box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void MinMaxAABoxClass::Add_Box(const Vector3 & min_corner,const Vector3 & max_corner)
{
assert(max_corner.X >= min_corner.X);
assert(max_corner.Y >= min_corner.Y);
assert(max_corner.Z >= min_corner.Z);
if (min_corner == max_corner) return;
MinCorner.Update_Min(min_corner);
MaxCorner.Update_Max(max_corner);
}
/***********************************************************************************************
* MinMaxAABoxClass::Transform -- Updates this box to enclose its transformed version *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void MinMaxAABoxClass::Transform(const Matrix3D & tm)
{
Vector3 oldmin = MinCorner;
Vector3 oldmax = MaxCorner;
tm.Transform_Min_Max_AABox(oldmin,oldmax,&MinCorner,&MaxCorner);
}
/***********************************************************************************************
* MinMaxAABoxClass::Translate -- translates the box *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 7/31/98 GTH : Created. *
*=============================================================================================*/
WWINLINE void MinMaxAABoxClass::Translate(const Vector3 & pos)
{
MinCorner+=pos;
MaxCorner+=pos;
}
#endif