mirror of
https://github.com/electronicarts/CnC_Generals_Zero_Hour.git
synced 2025-12-19 00:51:41 -05:00
Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.
This commit is contained in:
143
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/Vector3i.h
Normal file
143
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/Vector3i.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/vector3i.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 11/24/01 5:24p $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef VECTOR3I_H
|
||||
#define VECTOR3I_H
|
||||
|
||||
#include "always.h"
|
||||
|
||||
class Vector3i
|
||||
{
|
||||
public:
|
||||
|
||||
int I;
|
||||
int J;
|
||||
int K;
|
||||
|
||||
WWINLINE Vector3i(void);
|
||||
WWINLINE Vector3i(int i,int j,int k);
|
||||
|
||||
WWINLINE bool operator== (const Vector3i & v) const;
|
||||
WWINLINE bool operator!= (const Vector3i& v) const;
|
||||
WWINLINE const int& operator[] (int n) const;
|
||||
WWINLINE int& operator[] (int n);
|
||||
};
|
||||
|
||||
|
||||
WWINLINE Vector3i::Vector3i(void)
|
||||
{
|
||||
}
|
||||
|
||||
WWINLINE Vector3i::Vector3i(int i,int j,int k)
|
||||
{
|
||||
I = i; J = j; K = k;
|
||||
}
|
||||
|
||||
WWINLINE bool Vector3i::operator == (const Vector3i & v) const
|
||||
{
|
||||
return (I == v.I && J == v.J && K == v.K);
|
||||
}
|
||||
|
||||
WWINLINE bool Vector3i::operator != (const Vector3i& v) const
|
||||
{
|
||||
return !(I == v.I && J == v.J && K == v.K);
|
||||
}
|
||||
|
||||
WWINLINE const int& Vector3i::operator[] (int n) const
|
||||
{
|
||||
return ((int*)this)[n];
|
||||
}
|
||||
|
||||
WWINLINE int& Vector3i::operator[] (int n)
|
||||
{
|
||||
return ((int*)this)[n];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class Vector3i16
|
||||
{
|
||||
public:
|
||||
|
||||
unsigned short I;
|
||||
unsigned short J;
|
||||
unsigned short K;
|
||||
|
||||
WWINLINE Vector3i16(void);
|
||||
WWINLINE Vector3i16(unsigned short i,unsigned short j,unsigned short k);
|
||||
|
||||
WWINLINE bool operator== (const Vector3i & v) const;
|
||||
WWINLINE bool operator!= (const Vector3i& v) const;
|
||||
WWINLINE const unsigned short & operator[] (int n) const;
|
||||
WWINLINE unsigned short & operator[] (int n);
|
||||
};
|
||||
|
||||
|
||||
WWINLINE Vector3i16::Vector3i16(void)
|
||||
{
|
||||
}
|
||||
|
||||
WWINLINE Vector3i16::Vector3i16(unsigned short i,unsigned short j,unsigned short k)
|
||||
{
|
||||
I = i; J = j; K = k;
|
||||
}
|
||||
|
||||
WWINLINE bool Vector3i16::operator == (const Vector3i & v) const
|
||||
{
|
||||
return (I == v.I && J == v.J && K == v.K);
|
||||
}
|
||||
|
||||
WWINLINE bool Vector3i16::operator != (const Vector3i& v) const
|
||||
{
|
||||
return !(I == v.I && J == v.J && K == v.K);
|
||||
}
|
||||
|
||||
WWINLINE const unsigned short & Vector3i16::operator[] (int n) const
|
||||
{
|
||||
return ((unsigned short *)this)[n];
|
||||
}
|
||||
|
||||
WWINLINE unsigned short & Vector3i16::operator[] (int n)
|
||||
{
|
||||
return ((unsigned short *)this)[n];
|
||||
}
|
||||
|
||||
#endif
|
||||
79
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aabox.cpp
Normal file
79
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aabox.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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.cpp $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 5/08/01 6:33p $*
|
||||
* *
|
||||
* $Revision:: 18 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* AABoxClass::Init_Random -- initializes this box to a random state *
|
||||
* AABoxClass::Contains -- test whether this box contains the given point *
|
||||
* AABoxClass::Contains -- Test whether this box contains the given box *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "aabox.h"
|
||||
#include "colmath.h"
|
||||
#include "colmathinlines.h"
|
||||
#include <float.h>
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* AABoxClass::Init_Random -- initializes this box to a random state *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/17/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void AABoxClass::Init_Random(float min_center,float max_center,float min_extent,float max_extent)
|
||||
{
|
||||
Center.X = min_center + WWMath::Random_Float() * (max_center - min_center);
|
||||
Center.Y = min_center + WWMath::Random_Float() * (max_center - min_center);
|
||||
Center.Z = min_center + WWMath::Random_Float() * (max_center - min_center);
|
||||
|
||||
Extent.X = min_extent + WWMath::Random_Float() * (max_extent - min_extent);
|
||||
Extent.Y = min_extent + WWMath::Random_Float() * (max_extent - min_extent);
|
||||
Extent.Z = min_extent + WWMath::Random_Float() * (max_extent - min_extent);
|
||||
}
|
||||
|
||||
|
||||
void AABoxClass::Transform(const Matrix3D & tm,const AABoxClass & in,AABoxClass * out)
|
||||
{
|
||||
tm.Transform_Center_Extent_AABox(in.Center,in.Extent,&(out->Center),&(out->Extent));
|
||||
}
|
||||
|
||||
void MinMaxAABoxClass::Init_Empty(void)
|
||||
{
|
||||
MinCorner.Set(FLT_MAX,FLT_MAX,FLT_MAX);
|
||||
MaxCorner.Set(-FLT_MAX,-FLT_MAX,-FLT_MAX);
|
||||
}
|
||||
679
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aabox.h
Normal file
679
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aabox.h
Normal file
@@ -0,0 +1,679 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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
|
||||
1616
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aabtreecull.cpp
Normal file
1616
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aabtreecull.cpp
Normal file
File diff suppressed because it is too large
Load Diff
344
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aabtreecull.h
Normal file
344
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aabtreecull.h
Normal file
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/aabtreecull.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 7/24/01 10:00a $*
|
||||
* *
|
||||
* $Revision:: 15 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef AABTREECULL_H
|
||||
#define AABTREECULL_H
|
||||
|
||||
#include "cullsys.h"
|
||||
#include "aaplane.h"
|
||||
#include "wwmath.h"
|
||||
#include "mempool.h"
|
||||
#include "simplevec.h"
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
class AABTreeNodeClass;
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
class SphereClass;
|
||||
|
||||
/**
|
||||
** AABTreeCullSystemClass
|
||||
** Derived culling system that uses an Axis-Aligned Bounding Box Tree
|
||||
*/
|
||||
class AABTreeCullSystemClass : public CullSystemClass
|
||||
{
|
||||
public:
|
||||
|
||||
AABTreeCullSystemClass(void);
|
||||
virtual ~AABTreeCullSystemClass(void);
|
||||
|
||||
/*
|
||||
** Re-partition the tree. Two methods can be used to accomplish this. The
|
||||
** first re-partitions the tree based on the objects contained within, the second
|
||||
** re-partitions the tree based solely on a set of input "seed" boxes. Each seed
|
||||
** box will become a leaf; then the objects will be re-inserted in the new tree.
|
||||
*/
|
||||
void Re_Partition(void);
|
||||
void Re_Partition(const AABoxClass & bounds,SimpleDynVecClass<AABoxClass> & boxes);
|
||||
|
||||
/*
|
||||
** Update_Bounding_Boxes. This function causes all bounding boxes in the tree to update themselves.
|
||||
** If any box is found to not bound the objects it is supposed to contain, the box is updated
|
||||
** Note that this is normally not necessary, the reason this function existsis due to the fact
|
||||
** that the renegade level editor tries to do everything possible to not discard the precalculated
|
||||
** visibilty data for a level. In some cases, we want to load geometry that has been edited back
|
||||
** into the same AABTree without re-partitioning.
|
||||
*/
|
||||
void Update_Bounding_Boxes(void);
|
||||
|
||||
/*
|
||||
** Re-insert an object into the tree
|
||||
*/
|
||||
virtual void Update_Culling(CullableClass * obj);
|
||||
|
||||
/*
|
||||
** Statistics about the AAB-Tree
|
||||
*/
|
||||
int Partition_Node_Count(void) const;
|
||||
int Partition_Tree_Depth(void) const;
|
||||
int Object_Count(void) const;
|
||||
|
||||
/*
|
||||
** Collect objects which overlap the given primitive
|
||||
*/
|
||||
virtual void Collect_Objects(const Vector3 & point);
|
||||
virtual void Collect_Objects(const AABoxClass & box);
|
||||
virtual void Collect_Objects(const OBBoxClass & box);
|
||||
virtual void Collect_Objects(const FrustumClass & frustum);
|
||||
virtual void Collect_Objects(const SphereClass & sphere);
|
||||
|
||||
/*
|
||||
** Load and Save a description of this AAB-Tree and its contents
|
||||
*/
|
||||
virtual void Load(ChunkLoadClass & cload);
|
||||
virtual void Save(ChunkSaveClass & csave);
|
||||
|
||||
/*
|
||||
** Save an objects linkage, load the linkage and re-link the object
|
||||
*/
|
||||
void Load_Object_Linkage(ChunkLoadClass & cload,CullableClass * obj);
|
||||
void Save_Object_Linkage(ChunkSaveClass & csave,CullableClass * obj);
|
||||
|
||||
/*
|
||||
** Bounding box of the entire tree
|
||||
*/
|
||||
const AABoxClass & Get_Bounding_Box(void);
|
||||
void Get_Node_Bounds(int node_id,AABoxClass * set_bounds);
|
||||
|
||||
/*
|
||||
** Statistics
|
||||
*/
|
||||
struct StatsStruct
|
||||
{
|
||||
int NodeCount;
|
||||
int NodesAccepted;
|
||||
int NodesTriviallyAccepted;
|
||||
int NodesRejected;
|
||||
};
|
||||
|
||||
void Reset_Statistics(void);
|
||||
const StatsStruct & Get_Statistics(void);
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
** Internal stat tracking
|
||||
*/
|
||||
#ifdef WWDEBUG
|
||||
void NODE_ACCEPTED(void) { Stats.NodesAccepted ++; }
|
||||
void NODE_TRIVIALLY_ACCEPTED(void) { Stats.NodesTriviallyAccepted ++; }
|
||||
void NODE_REJECTED(void) { Stats.NodesRejected ++; }
|
||||
#else
|
||||
void NODE_ACCEPTED(void) { }
|
||||
void NODE_TRIVIALLY_ACCEPTED(void) { }
|
||||
void NODE_REJECTED(void) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Internal functions
|
||||
*/
|
||||
void Add_Object_Internal(CullableClass * obj,int node_index = -1);
|
||||
void Remove_Object_Internal(CullableClass * obj);
|
||||
|
||||
void Re_Index_Nodes(void);
|
||||
void Re_Index_Nodes_Recursive(AABTreeNodeClass * node,int & counter);
|
||||
|
||||
int Partition_Node_Count_Recursive(AABTreeNodeClass * node) const;
|
||||
void Partition_Tree_Depth_Recursive(AABTreeNodeClass * node,int cur_depth,int & max_depth) const;
|
||||
void Add_Object_Recursive(AABTreeNodeClass * node,CullableClass * obj);
|
||||
void Add_Loaded_Object(AABTreeNodeClass * node,CullableClass * obj);
|
||||
|
||||
void Collect_Objects_Recursive(AABTreeNodeClass * node);
|
||||
void Collect_Objects_Recursive(AABTreeNodeClass * node,const Vector3 & point);
|
||||
void Collect_Objects_Recursive(AABTreeNodeClass * node,const AABoxClass & box);
|
||||
void Collect_Objects_Recursive(AABTreeNodeClass * node,const OBBoxClass & box);
|
||||
void Collect_Objects_Recursive(AABTreeNodeClass * node,const FrustumClass & frustum);
|
||||
void Collect_Objects_Recursive(AABTreeNodeClass * node,const FrustumClass & frustum,int planes_passed);
|
||||
void Collect_Objects_Recursive(AABTreeNodeClass * node,const SphereClass & sphere);
|
||||
|
||||
void Update_Bounding_Boxes_Recursive(AABTreeNodeClass * node);
|
||||
|
||||
void Load_Nodes(AABTreeNodeClass * node,ChunkLoadClass & cload);
|
||||
void Save_Nodes(AABTreeNodeClass * node,ChunkSaveClass & csave);
|
||||
|
||||
virtual void Load_Node_Contents(AABTreeNodeClass * /*node*/,ChunkLoadClass & /*cload*/) { }
|
||||
virtual void Save_Node_Contents(AABTreeNodeClass * /*node*/,ChunkSaveClass & /*csave*/) { }
|
||||
|
||||
AABTreeNodeClass * RootNode; // root of the AAB-Tree
|
||||
int ObjectCount; // number of objects in the system
|
||||
|
||||
int NodeCount; // number of nodes
|
||||
AABTreeNodeClass ** IndexedNodes; // index access to the nodes
|
||||
|
||||
StatsStruct Stats;
|
||||
|
||||
friend class AABTreeIterator;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** AABTreeIterator
|
||||
** This iterator allows the user to walk a tree. It can return the index of the current
|
||||
** node and the bounds of the current node.
|
||||
*/
|
||||
class AABTreeIterator
|
||||
{
|
||||
public:
|
||||
AABTreeIterator(AABTreeCullSystemClass * tree);
|
||||
|
||||
void Reset(void);
|
||||
bool Enter_Parent(void);
|
||||
bool Enter_Sibling(void);
|
||||
bool Has_Front_Child(void);
|
||||
bool Enter_Front_Child(void);
|
||||
bool Has_Back_Child(void);
|
||||
bool Enter_Back_Child(void);
|
||||
|
||||
int Get_Current_Node_Index(void);
|
||||
void Get_Current_Box(AABoxClass * set_box);
|
||||
|
||||
private:
|
||||
|
||||
void validate(void);
|
||||
|
||||
AABTreeCullSystemClass * Tree;
|
||||
int CurNodeIndex;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** TypedAABTreeCullSystemClass
|
||||
** This template adds type-safety to an AABTree. It allows you to create trees
|
||||
** containing a particular type of object (the class must be derived from CullableClass though)
|
||||
*/
|
||||
template <class T> class TypedAABTreeCullSystemClass : public AABTreeCullSystemClass
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void Add_Object(T * obj,int node_index=-1) { Add_Object_Internal(obj,node_index); }
|
||||
virtual void Remove_Object(T * obj) { Remove_Object_Internal(obj); }
|
||||
|
||||
T * Get_First_Collected_Object(void) { return (T*)Get_First_Collected_Object_Internal(); }
|
||||
T * Get_Next_Collected_Object(T * obj) { return (T*)Get_Next_Collected_Object_Internal(obj); }
|
||||
T * Peek_First_Collected_Object(void) { return (T*)Peek_First_Collected_Object_Internal(); }
|
||||
T * Peek_Next_Collected_Object(T * obj) { return (T*)Peek_Next_Collected_Object_Internal(obj); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
** AABTreeNodeClass - the aab-tree is built out of these objects
|
||||
** CullableClass's can be linked into any of these nodes. Whenever the
|
||||
** tree is re-built, all objects will end up in the leaf nodes. Between
|
||||
** re-builds, as objects are added, they will be placed as deep into the
|
||||
** tree as possible.
|
||||
*/
|
||||
class AABTreeNodeClass : public AutoPoolClass<AABTreeNodeClass,256>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
AABTreeNodeClass(void);
|
||||
~AABTreeNodeClass(void);
|
||||
|
||||
void Add_Object(CullableClass * obj,bool update_bounds = true);
|
||||
void Remove_Object(CullableClass * obj);
|
||||
int Object_Count(void);
|
||||
CullableClass * Peek_Object(int index);
|
||||
|
||||
uint32 Index; // Index of this node
|
||||
AABoxClass Box; // Bounding box of the node
|
||||
AABTreeNodeClass * Parent; // parent of this node
|
||||
AABTreeNodeClass * Front; // front node
|
||||
AABTreeNodeClass * Back; // back node
|
||||
CullableClass * Object; // objects in this node
|
||||
uint32 UserData; // 32bit field for the user, initialized to 0
|
||||
|
||||
/*
|
||||
** Construction support:
|
||||
*/
|
||||
struct SplitChoiceStruct
|
||||
{
|
||||
SplitChoiceStruct(void) : Cost(FLT_MAX),FrontCount(0),BackCount(0),Plane(AAPlaneClass::XNORMAL,0.0f)
|
||||
{
|
||||
FrontBox.Init_Empty();
|
||||
BackBox.Init_Empty();
|
||||
}
|
||||
|
||||
float Cost;
|
||||
int FrontCount;
|
||||
int BackCount;
|
||||
MinMaxAABoxClass FrontBox;
|
||||
MinMaxAABoxClass BackBox;
|
||||
AAPlaneClass Plane;
|
||||
};
|
||||
|
||||
void Compute_Bounding_Box(void);
|
||||
void Compute_Local_Bounding_Box(void);
|
||||
float Compute_Volume(void);
|
||||
void Transfer_Objects(AABTreeNodeClass * dummy_node);
|
||||
|
||||
/*
|
||||
** Partition the tree based on the objects contained.
|
||||
*/
|
||||
void Partition(void);
|
||||
void Split_Objects( const SplitChoiceStruct & sc,
|
||||
AABTreeNodeClass * front,
|
||||
AABTreeNodeClass * back);
|
||||
|
||||
/*
|
||||
** Partition the tree based on a set of input "seed" boxes.
|
||||
*/
|
||||
void Partition(const AABoxClass & bounds,SimpleDynVecClass<AABoxClass> & boxes);
|
||||
void Split_Boxes( const SplitChoiceStruct & sc,
|
||||
SimpleDynVecClass<AABoxClass> & boxes,
|
||||
SimpleDynVecClass<AABoxClass> & frontboxes,
|
||||
SimpleDynVecClass<AABoxClass> & backboxes);
|
||||
|
||||
/*
|
||||
** Functions used by both partitioning algorithms
|
||||
*/
|
||||
void Select_Splitting_Plane(SplitChoiceStruct * sc,SimpleDynVecClass<AABoxClass> & boxes);
|
||||
void Select_Splitting_Plane_Brute_Force(SplitChoiceStruct * sc,SimpleDynVecClass<AABoxClass> & boxes);
|
||||
void Compute_Score(SplitChoiceStruct * sc,SimpleDynVecClass<AABoxClass> & boxes);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** AABTreeLinkClass
|
||||
** This structure is used to link objects into an AAB-Tree culling system.
|
||||
*/
|
||||
class AABTreeLinkClass : public CullLinkClass, public AutoPoolClass<AABTreeLinkClass,256>
|
||||
{
|
||||
public:
|
||||
AABTreeLinkClass(AABTreeCullSystemClass * system) : CullLinkClass(system),Node(NULL), NextObject(NULL) { }
|
||||
|
||||
AABTreeNodeClass * Node; // partition node containing this object
|
||||
CullableClass * NextObject; // next object in the node
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // AABTREECULL_H
|
||||
83
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aaplane.h
Normal file
83
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/aaplane.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/aaplane.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 5/19/00 3:12p $*
|
||||
* *
|
||||
* $Revision:: 8 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef AAPLANE_H
|
||||
#define AAPLANE_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector3.h"
|
||||
|
||||
|
||||
/*
|
||||
** This class is used to describe an "axis-aligned" plane. I.e, the normal
|
||||
** of the plane is one of the three coordinate axes.
|
||||
*/
|
||||
class AAPlaneClass
|
||||
{
|
||||
public:
|
||||
|
||||
enum AxisEnum { XNORMAL = 0, YNORMAL = 1, ZNORMAL = 2 };
|
||||
|
||||
AAPlaneClass(void) { }
|
||||
AAPlaneClass(AxisEnum normal,float dist) : Normal(normal),Dist(dist) { }
|
||||
|
||||
void Set(AxisEnum normal,float dist);
|
||||
void Get_Normal(Vector3 * normal) const;
|
||||
|
||||
public:
|
||||
|
||||
AxisEnum Normal;
|
||||
float Dist;
|
||||
|
||||
};
|
||||
|
||||
inline void AAPlaneClass::Set(AxisEnum normal,float dist)
|
||||
{
|
||||
Normal = normal;
|
||||
Dist = dist;
|
||||
}
|
||||
|
||||
inline void AAPlaneClass::Get_Normal(Vector3 * normal) const
|
||||
{
|
||||
normal->Set(0,0,0);
|
||||
(*normal)[Normal] = 1.0f;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/cardinalspline.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 9/16/01 4:07p $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "cardinalspline.h"
|
||||
#include "wwdebug.h"
|
||||
#include "persistfactory.h"
|
||||
#include "wwmathids.h"
|
||||
#include "wwhack.h"
|
||||
|
||||
/*
|
||||
** Force-Link this module because the linker can't detect that we actually need it...
|
||||
*/
|
||||
DECLARE_FORCE_LINK(cardinalspline);
|
||||
|
||||
|
||||
/*
|
||||
** Save-Load stuff
|
||||
*/
|
||||
SimplePersistFactoryClass<CardinalSpline3DClass,WWMATH_CHUNKID_CARDINALSPLINE3D> _CardinalSpline3DFactory;
|
||||
SimplePersistFactoryClass<CardinalSpline1DClass,WWMATH_CHUNKID_CARDINALSPLINE1D> _CardinalSpline1DFactory;
|
||||
|
||||
enum
|
||||
{
|
||||
// ID's used by CardinalSpline3D
|
||||
CARDINAL3D_CHUNK_HERMITE3D = 0x02070957,
|
||||
CARDINAL3D_CHUNK_TIGHTNESSKEYS,
|
||||
|
||||
// ID's used by CardinalSpline1D
|
||||
CARDINAL1D_CHUNK_HERMITE1D = 0x02070959,
|
||||
CARDINAL1D_CHUNK_TIGHTNESSKEYS
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** CardinalSpline3DClass Implementation
|
||||
*/
|
||||
int CardinalSpline3DClass::Add_Key(const Vector3 & point,float t)
|
||||
{
|
||||
int index = HermiteSpline3DClass::Add_Key(point,t);
|
||||
float tightness = 0.5f;
|
||||
Tightness.Insert(index,tightness);
|
||||
return index;
|
||||
}
|
||||
|
||||
void CardinalSpline3DClass::Remove_Key(int i)
|
||||
{
|
||||
Tightness.Delete(i);
|
||||
HermiteSpline3DClass::Remove_Key(i);
|
||||
}
|
||||
|
||||
void CardinalSpline3DClass::Clear_Keys(void)
|
||||
{
|
||||
Tightness.Clear();
|
||||
HermiteSpline3DClass::Clear_Keys();
|
||||
}
|
||||
|
||||
void CardinalSpline3DClass::Set_Tightness(int i,float tightness)
|
||||
{
|
||||
WWASSERT(i >= 0);
|
||||
WWASSERT(i < Tightness.Count());
|
||||
Tightness[i] = tightness;
|
||||
TangentsDirty = true;
|
||||
}
|
||||
|
||||
float CardinalSpline3DClass::Get_Tightness(int i)
|
||||
{
|
||||
return Tightness[i];
|
||||
}
|
||||
|
||||
void CardinalSpline3DClass::Update_Tangents(void)
|
||||
{
|
||||
if (Keys.Count() < 2) {
|
||||
for (int i=0; i<Keys.Count(); i++) {
|
||||
Tangents[0].InTangent.Set(0,0,0);
|
||||
Tangents[0].OutTangent.Set(0,0,0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// First and Last Key:
|
||||
// Only need to compute the OutTangent for key[0] and the InTangent for key[end]
|
||||
int end = Keys.Count() - 1;
|
||||
Tangents[0].InTangent.Set(0,0,0);
|
||||
Tangents[end].OutTangent.Set(0,0,0);
|
||||
|
||||
if (IsLooping) {
|
||||
|
||||
// This really only works if the start and end points have the same position...
|
||||
Tangents[0].OutTangent.X = (1.0f - Tightness[0])*(Keys[1].Point.X - Keys[end-1].Point.X);
|
||||
Tangents[0].OutTangent.Y = (1.0f - Tightness[0])*(Keys[1].Point.Y - Keys[end-1].Point.Y);
|
||||
Tangents[0].OutTangent.Z = (1.0f - Tightness[0])*(Keys[1].Point.Z - Keys[end-1].Point.Z);
|
||||
Tangents[end].InTangent = Tangents[0].OutTangent;
|
||||
|
||||
} else {
|
||||
|
||||
Tangents[0].OutTangent.X = (1.0f - Tightness[0])*(Keys[1].Point.X - Keys[0].Point.X);
|
||||
Tangents[0].OutTangent.Y = (1.0f - Tightness[0])*(Keys[1].Point.Y - Keys[0].Point.Y);
|
||||
Tangents[0].OutTangent.Z = (1.0f - Tightness[0])*(Keys[1].Point.Z - Keys[0].Point.Z);
|
||||
|
||||
Tangents[end].InTangent.X = (1.0f - Tightness[0])*(Keys[end].Point.X - Keys[end-1].Point.X);
|
||||
Tangents[end].InTangent.Y = (1.0f - Tightness[0])*(Keys[end].Point.Y - Keys[end-1].Point.Y);
|
||||
Tangents[end].InTangent.Z = (1.0f - Tightness[0])*(Keys[end].Point.Z - Keys[end-1].Point.Z);
|
||||
|
||||
}
|
||||
|
||||
float total_time = (Keys[1].Time - Keys[0].Time) + (Keys[end].Time - Keys[end-1].Time);
|
||||
float in_factor = 2.0f * (Keys[end].Time - Keys[end-1].Time) / total_time;
|
||||
float out_factor = 2.0f * (Keys[1].Time - Keys[0].Time) / total_time;
|
||||
Tangents[end].InTangent *= in_factor;
|
||||
Tangents[0].OutTangent *= out_factor;
|
||||
|
||||
|
||||
// inner knots
|
||||
for (int i=1; i<Keys.Count()-1; i++) {
|
||||
Tangents[i].InTangent.X = (1.0f - Tightness[i])*(Keys[i+1].Point.X - Keys[i-1].Point.X);
|
||||
Tangents[i].InTangent.Y = (1.0f - Tightness[i])*(Keys[i+1].Point.Y - Keys[i-1].Point.Y);
|
||||
Tangents[i].InTangent.Z = (1.0f - Tightness[i])*(Keys[i+1].Point.Z - Keys[i-1].Point.Z);
|
||||
Tangents[i].OutTangent = Tangents[i].InTangent;
|
||||
|
||||
float in_factor = 2.0f * (Keys[i].Time - Keys[i-1].Time) / (Keys[i+1].Time - Keys[i-1].Time);
|
||||
float out_factor = 2.0f * (Keys[i+1].Time - Keys[i].Time) / (Keys[i+1].Time - Keys[i-1].Time);
|
||||
|
||||
Tangents[i].InTangent *= in_factor; // compensating for the un-even keys
|
||||
Tangents[i].OutTangent *= out_factor;
|
||||
}
|
||||
TangentsDirty = false;
|
||||
}
|
||||
|
||||
const PersistFactoryClass & CardinalSpline3DClass::Get_Factory(void) const
|
||||
{
|
||||
return _CardinalSpline3DFactory;
|
||||
}
|
||||
|
||||
bool CardinalSpline3DClass::Save(ChunkSaveClass &csave)
|
||||
{
|
||||
csave.Begin_Chunk(CARDINAL3D_CHUNK_HERMITE3D);
|
||||
HermiteSpline3DClass::Save(csave);
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.Begin_Chunk(CARDINAL3D_CHUNK_TIGHTNESSKEYS);
|
||||
for (int i=0; i<Tightness.Count(); i++) {
|
||||
float tightness = Tightness[i];
|
||||
csave.Write(&(tightness),sizeof(tightness));
|
||||
}
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CardinalSpline3DClass::Load(ChunkLoadClass &cload)
|
||||
{
|
||||
int i;
|
||||
float tightness;
|
||||
|
||||
// reset the array of tightness keys
|
||||
Tightness.Delete_All();
|
||||
|
||||
// read in the chunks
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case CARDINAL3D_CHUNK_HERMITE3D:
|
||||
HermiteSpline3DClass::Load(cload);
|
||||
break;
|
||||
|
||||
case CARDINAL3D_CHUNK_TIGHTNESSKEYS:
|
||||
for (i=0; i<Keys.Count(); i++) {
|
||||
cload.Read(&(tightness),sizeof(tightness));
|
||||
Tightness.Add(tightness);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** CardinalSpline1DClass Implementation
|
||||
*/
|
||||
int CardinalSpline1DClass::Add_Key(float point,float t)
|
||||
{
|
||||
int index = HermiteSpline1DClass::Add_Key(point,t);
|
||||
float tightness = 0.5f;
|
||||
Tightness.Insert(index,tightness);
|
||||
return index;
|
||||
}
|
||||
|
||||
void CardinalSpline1DClass::Remove_Key(int i)
|
||||
{
|
||||
Tightness.Delete(i);
|
||||
HermiteSpline1DClass::Remove_Key(i);
|
||||
}
|
||||
|
||||
void CardinalSpline1DClass::Clear_Keys(void)
|
||||
{
|
||||
Tightness.Clear();
|
||||
HermiteSpline1DClass::Clear_Keys();
|
||||
}
|
||||
|
||||
void CardinalSpline1DClass::Set_Tightness(int i,float tightness)
|
||||
{
|
||||
WWASSERT(i >= 0);
|
||||
WWASSERT(i < Tightness.Count());
|
||||
Tightness[i] = tightness;
|
||||
TangentsDirty = true;
|
||||
}
|
||||
|
||||
float CardinalSpline1DClass::Get_Tightness(int i)
|
||||
{
|
||||
return Tightness[i];
|
||||
}
|
||||
|
||||
void CardinalSpline1DClass::Update_Tangents(void)
|
||||
{
|
||||
if (Keys.Count() < 2) {
|
||||
for (int i=0; i<Keys.Count(); i++) {
|
||||
Tangents[0].InTangent = 0;
|
||||
Tangents[0].OutTangent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// First and Last Key:
|
||||
// Only need to compute the OutTangent for key[0] and the InTangent for key[end]
|
||||
int end = Keys.Count() - 1;
|
||||
Tangents[0].InTangent = 0;
|
||||
Tangents[end].OutTangent = 0;
|
||||
|
||||
if (IsLooping) {
|
||||
|
||||
// This really only works if the start and end points have the same position...
|
||||
Tangents[0].OutTangent = (1.0f - Tightness[0])*(Keys[1].Point - Keys[end-1].Point);
|
||||
Tangents[end].InTangent = Tangents[0].OutTangent;
|
||||
|
||||
} else {
|
||||
|
||||
Tangents[0].OutTangent = (1.0f - Tightness[0])*(Keys[1].Point - Keys[0].Point);
|
||||
Tangents[end].InTangent = (1.0f - Tightness[0])*(Keys[end].Point - Keys[end-1].Point);
|
||||
}
|
||||
|
||||
float total_time = (Keys[1].Time - Keys[0].Time) + (Keys[end].Time - Keys[end-1].Time);
|
||||
float in_factor = 2.0f * (Keys[end].Time - Keys[end-1].Time) / total_time;
|
||||
float out_factor = 2.0f * (Keys[1].Time - Keys[0].Time) / total_time;
|
||||
Tangents[end].InTangent *= in_factor;
|
||||
Tangents[0].OutTangent *= out_factor;
|
||||
|
||||
|
||||
// inner knots
|
||||
for (int i=1; i<Keys.Count()-1; i++) {
|
||||
Tangents[i].InTangent = (1.0f - Tightness[i])*(Keys[i+1].Point - Keys[i-1].Point);
|
||||
Tangents[i].OutTangent = Tangents[i].InTangent;
|
||||
|
||||
float in_factor = 2.0f * (Keys[i].Time - Keys[i-1].Time) / (Keys[i+1].Time - Keys[i-1].Time);
|
||||
float out_factor = 2.0f * (Keys[i+1].Time - Keys[i].Time) / (Keys[i+1].Time - Keys[i-1].Time);
|
||||
|
||||
Tangents[i].InTangent *= in_factor; // compensating for the un-even keys
|
||||
Tangents[i].OutTangent *= out_factor;
|
||||
}
|
||||
TangentsDirty = false;
|
||||
}
|
||||
|
||||
const PersistFactoryClass & CardinalSpline1DClass::Get_Factory(void) const
|
||||
{
|
||||
return _CardinalSpline1DFactory;
|
||||
}
|
||||
|
||||
bool CardinalSpline1DClass::Save(ChunkSaveClass &csave)
|
||||
{
|
||||
csave.Begin_Chunk(CARDINAL1D_CHUNK_HERMITE1D);
|
||||
HermiteSpline1DClass::Save(csave);
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.Begin_Chunk(CARDINAL1D_CHUNK_TIGHTNESSKEYS);
|
||||
for (int i=0; i<Tightness.Count(); i++) {
|
||||
float tightness = Tightness[i];
|
||||
csave.Write(&(tightness),sizeof(tightness));
|
||||
}
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CardinalSpline1DClass::Load(ChunkLoadClass &cload)
|
||||
{
|
||||
int i;
|
||||
float tightness;
|
||||
|
||||
// reset the array of tangents
|
||||
Tightness.Delete_All();
|
||||
|
||||
// read in the chunks
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case CARDINAL1D_CHUNK_HERMITE1D:
|
||||
HermiteSpline1DClass::Load(cload);
|
||||
break;
|
||||
|
||||
case CARDINAL1D_CHUNK_TIGHTNESSKEYS:
|
||||
for (i=0; i<Keys.Count(); i++) {
|
||||
cload.Read(&(tightness),sizeof(tightness));
|
||||
Tightness.Add(tightness);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
104
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/cardinalspline.h
Normal file
104
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/cardinalspline.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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:: /VSS_Sync/wwmath/cardinalspline.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 6/13/01 2:18p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef CARDINALSPLINE_H
|
||||
#define CARDINALSPLINE_H
|
||||
|
||||
#include "hermitespline.h"
|
||||
|
||||
/**
|
||||
** CardinalSpline3DClass
|
||||
** 3-Dimensional cardinal splines
|
||||
*/
|
||||
class CardinalSpline3DClass : public HermiteSpline3DClass
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int Add_Key(const Vector3 & point,float t);
|
||||
virtual void Remove_Key(int i);
|
||||
virtual void Clear_Keys(void);
|
||||
|
||||
virtual void Set_Tightness(int i,float tightness);
|
||||
virtual float Get_Tightness(int i);
|
||||
|
||||
virtual void Update_Tangents(void);
|
||||
|
||||
// save-load support
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
|
||||
protected:
|
||||
|
||||
DynamicVectorClass<float> Tightness;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** CardinalSpline1DClass
|
||||
** 1-Dimensional cardinal splines
|
||||
*/
|
||||
class CardinalSpline1DClass : public HermiteSpline1DClass
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int Add_Key(float point,float t);
|
||||
virtual void Remove_Key(int i);
|
||||
virtual void Clear_Keys(void);
|
||||
|
||||
virtual void Set_Tightness(int i,float tightness);
|
||||
virtual float Get_Tightness(int i);
|
||||
|
||||
virtual void Update_Tangents(void);
|
||||
|
||||
// save-load support
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
|
||||
protected:
|
||||
|
||||
DynamicVectorClass<float> Tightness;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
75
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/castres.h
Normal file
75
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/castres.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/castres.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 11/14/00 2:59p $*
|
||||
* *
|
||||
* $Revision:: 10 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef CASTRES_H
|
||||
#define CASTRES_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector3.h"
|
||||
#include "bittype.h"
|
||||
|
||||
|
||||
/**
|
||||
** CastResultStruct
|
||||
** Result of a volume or ray cast operation will be stored in the following structure
|
||||
** NOTE: If you can avoid it, do not enable ComputeContactPoint. When casting rays, it is more
|
||||
** efficient to use the resulting Fraction to compute the contact point outside of the
|
||||
** collision detection code. In the case of AABox sweeping for character collision detection,
|
||||
** you don't usually need the actual point of contact, etc etc.
|
||||
**
|
||||
** The default state of ComputeContactPoint is *false*
|
||||
*/
|
||||
struct CastResultStruct
|
||||
{
|
||||
CastResultStruct(void) { Reset(); }
|
||||
void Reset(void) { StartBad = false; Fraction = 1.0f; Normal.Set(0,0,0); SurfaceType = 0; ComputeContactPoint = false; ContactPoint.Set(0,0,0); }
|
||||
|
||||
bool StartBad; // was the inital configuration interpenetrating something?
|
||||
float Fraction; // fraction of the move up until collision
|
||||
Vector3 Normal; // surface normal at the collision point
|
||||
uint32 SurfaceType; // surface type of polygon at collision point (see W3D_SURFACE_TYPES in w3d_file.h)
|
||||
|
||||
bool ComputeContactPoint; // This signals the collision code to compute the point of collision
|
||||
Vector3 ContactPoint; // This will be set to the point of collision if ComputeContactPoint is true
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/catmullromspline.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 3/08/00 8:50p $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* CatmullRomSpline3DClass::Update_Tangents -- computes the tangents at each key *
|
||||
* CatmullRomSpline3DClass::Get_Factory -- returns the factory for CatmullRomSpline3D *
|
||||
* CatmullRomSpline3DClass::Save -- save this curve *
|
||||
* CatmullRomSpline3DClass::Load -- load this curve *
|
||||
* CatmullRomSpline1DClass::Update_Tangents -- Computes the tangents at each key *
|
||||
* CatmullRomSpline1DClass::Get_Factory -- returns the factory for CatmullRomSpline1D *
|
||||
* CatmullRomSpline1DClass::Save -- Save this curve *
|
||||
* CatmullRomSpline1DClass::Load -- Load this curve *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "catmullromspline.h"
|
||||
#include "persistfactory.h"
|
||||
#include "wwmathids.h"
|
||||
#include "wwhack.h"
|
||||
|
||||
/*
|
||||
** Force-Link this module because the linker can't detect that we actually need it...
|
||||
*/
|
||||
DECLARE_FORCE_LINK(catmullromspline);
|
||||
|
||||
/*
|
||||
** Save-Load stuff
|
||||
*/
|
||||
SimplePersistFactoryClass<CatmullRomSpline3DClass,WWMATH_CHUNKID_CATMULLROMSPLINE3D> _CatmullRomSpline3DFactory;
|
||||
SimplePersistFactoryClass<CatmullRomSpline1DClass,WWMATH_CHUNKID_CATMULLROMSPLINE1D> _CatmullRomSpline1DFactory;
|
||||
|
||||
enum
|
||||
{
|
||||
// ID's used by CatmullRomSpline3D
|
||||
CATMULLROM3D_CHUNK_HERMITE3D = 0x00020727,
|
||||
|
||||
// ID's used by CatmullRomSpline1D
|
||||
CATMULLROM1D_CHUNK_HERMITE1D = 0x00020729,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Catmull-Rom 3D spline implementation
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
* CatmullRomSpline3DClass::Update_Tangents -- computes the tangents at each key *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* I'm not sure about the tangents for the endpoints of the curve. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/7/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CatmullRomSpline3DClass::Update_Tangents(void)
|
||||
{
|
||||
if (Keys.Count() < 2) {
|
||||
for (int i=0; i<Keys.Count(); i++) {
|
||||
Tangents[0].InTangent.Set(0,0,0);
|
||||
Tangents[0].OutTangent.Set(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
// first and last knot
|
||||
int end = Keys.Count() - 1;
|
||||
Tangents[0].InTangent.Set(0,0,0);
|
||||
Tangents[end].OutTangent.Set(0,0,0);
|
||||
|
||||
if (IsLooping) {
|
||||
|
||||
// This really only works if the start and end points have the same position...
|
||||
Tangents[0].OutTangent.X = 0.5f*(Keys[1].Point.X - Keys[end-1].Point.X);
|
||||
Tangents[0].OutTangent.Y = 0.5f*(Keys[1].Point.Y - Keys[end-1].Point.Y);
|
||||
Tangents[0].OutTangent.Z = 0.5f*(Keys[1].Point.Z - Keys[end-1].Point.Z);
|
||||
Tangents[end].InTangent = Tangents[0].OutTangent;
|
||||
|
||||
} else {
|
||||
|
||||
// TODO: second derivative = 0... what is formula? I'm making this up...
|
||||
Tangents[0].OutTangent.X = 0.25f*(Keys[1].Point.X - Keys[0].Point.X);
|
||||
Tangents[0].OutTangent.Y = 0.25f*(Keys[1].Point.Y - Keys[0].Point.Y);
|
||||
Tangents[0].OutTangent.Z = 0.25f*(Keys[1].Point.Z - Keys[0].Point.Z);
|
||||
|
||||
Tangents[end].InTangent.X = 0.25f*(Keys[end].Point.X - Keys[end-1].Point.X);
|
||||
Tangents[end].InTangent.Y = 0.25f*(Keys[end].Point.Y - Keys[end-1].Point.Y);
|
||||
Tangents[end].InTangent.Z = 0.25f*(Keys[end].Point.Z - Keys[end-1].Point.Z);
|
||||
|
||||
}
|
||||
|
||||
float total_time = (Keys[1].Time - Keys[0].Time) + (Keys[end].Time - Keys[end-1].Time);
|
||||
float in_factor = 2.0f * (Keys[end].Time - Keys[end-1].Time) / total_time;
|
||||
float out_factor = 2.0f * (Keys[1].Time - Keys[0].Time) / total_time;
|
||||
Tangents[end].InTangent *= in_factor;
|
||||
Tangents[0].OutTangent *= out_factor;
|
||||
|
||||
// inner knots
|
||||
for (int i=1; i<Keys.Count()-1; i++) {
|
||||
Tangents[i].InTangent.X = 0.5f*(Keys[i+1].Point.X - Keys[i-1].Point.X);
|
||||
Tangents[i].InTangent.Y = 0.5f*(Keys[i+1].Point.Y - Keys[i-1].Point.Y);
|
||||
Tangents[i].InTangent.Z = 0.5f*(Keys[i+1].Point.Z - Keys[i-1].Point.Z);
|
||||
Tangents[i].OutTangent = Tangents[i].InTangent;
|
||||
|
||||
float in_factor = 2.0f * (Keys[i].Time - Keys[i-1].Time) / (Keys[i+1].Time - Keys[i-1].Time);
|
||||
float out_factor = 2.0f * (Keys[i+1].Time - Keys[i].Time) / (Keys[i+1].Time - Keys[i-1].Time);
|
||||
Tangents[i].InTangent *= in_factor; // compensating for the un-even keys
|
||||
Tangents[i].OutTangent *= out_factor;
|
||||
}
|
||||
TangentsDirty = false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CatmullRomSpline3DClass::Get_Factory -- returns the factory for CatmullRomSpline3D *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/7/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
const PersistFactoryClass & CatmullRomSpline3DClass::Get_Factory(void) const
|
||||
{
|
||||
return _CatmullRomSpline3DFactory;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CatmullRomSpline3DClass::Save -- save this curve *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/7/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CatmullRomSpline3DClass::Save(ChunkSaveClass &csave)
|
||||
{
|
||||
csave.Begin_Chunk(CATMULLROM3D_CHUNK_HERMITE3D);
|
||||
HermiteSpline3DClass::Save(csave);
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CatmullRomSpline3DClass::Load -- load this curve *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/7/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CatmullRomSpline3DClass::Load(ChunkLoadClass &cload)
|
||||
{
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case CATMULLROM3D_CHUNK_HERMITE3D:
|
||||
HermiteSpline3DClass::Load(cload);
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** The 1D Catmull-Rom implementation.
|
||||
*/
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CatmullRomSpline1DClass::Update_Tangents -- Computes the tangents at each key *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/7/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void CatmullRomSpline1DClass::Update_Tangents(void)
|
||||
{
|
||||
if (Keys.Count() < 2) {
|
||||
for (int i=0; i<Keys.Count(); i++) {
|
||||
Tangents[i].InTangent = 0.0f;
|
||||
Tangents[i].OutTangent = 0.0f;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// first and last knot
|
||||
int end = Keys.Count() - 1;
|
||||
Tangents[0].InTangent = 0.0f;
|
||||
Tangents[end].OutTangent = 0.0f;
|
||||
|
||||
if (IsLooping) {
|
||||
|
||||
// This really only works if the start and end points have the same position...
|
||||
Tangents[0].OutTangent = 0.5f*(Keys[1].Point - Keys[end-1].Point);
|
||||
Tangents[end].InTangent = Tangents[0].OutTangent;
|
||||
|
||||
} else {
|
||||
|
||||
// TODO: second derivative = 0... what is formula? I'm making this up...
|
||||
Tangents[0].OutTangent = 0.25f*(Keys[1].Point - Keys[0].Point);
|
||||
|
||||
Tangents[end].InTangent = 0.25f*(Keys[end].Point - Keys[end-1].Point);
|
||||
|
||||
}
|
||||
|
||||
float total_time = (Keys[1].Time - Keys[0].Time) + (Keys[end].Time - Keys[end-1].Time);
|
||||
float in_factor = 2.0f * (Keys[end].Time - Keys[end-1].Time) / total_time;
|
||||
float out_factor = 2.0f * (Keys[1].Time - Keys[0].Time) / total_time;
|
||||
Tangents[end].InTangent *= in_factor;
|
||||
Tangents[0].OutTangent *= out_factor;
|
||||
|
||||
// inner knots
|
||||
for (int i=1; i<Keys.Count()-1; i++) {
|
||||
Tangents[i].InTangent = 0.5f*(Keys[i+1].Point - Keys[i-1].Point);
|
||||
Tangents[i].OutTangent = Tangents[i].InTangent;
|
||||
|
||||
float in_factor = 2.0f * (Keys[i].Time - Keys[i-1].Time) / (Keys[i+1].Time - Keys[i-1].Time);
|
||||
float out_factor = 2.0f * (Keys[i+1].Time - Keys[i].Time) / (Keys[i+1].Time - Keys[i-1].Time);
|
||||
Tangents[i].InTangent *= in_factor; // compensating for the un-even keys
|
||||
Tangents[i].OutTangent *= out_factor;
|
||||
}
|
||||
TangentsDirty = false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CatmullRomSpline1DClass::Get_Factory -- returns the factory for CatmullRomSpline1D *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/7/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
const PersistFactoryClass & CatmullRomSpline1DClass::Get_Factory(void) const
|
||||
{
|
||||
return _CatmullRomSpline1DFactory;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CatmullRomSpline1DClass::Save -- Save this curve *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/7/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CatmullRomSpline1DClass::Save(ChunkSaveClass &csave)
|
||||
{
|
||||
csave.Begin_Chunk(CATMULLROM1D_CHUNK_HERMITE1D);
|
||||
HermiteSpline1DClass::Save(csave);
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CatmullRomSpline1DClass::Load -- Load this curve *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/7/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CatmullRomSpline1DClass::Load(ChunkLoadClass &cload)
|
||||
{
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case CATMULLROM1D_CHUNK_HERMITE1D:
|
||||
HermiteSpline1DClass::Load(cload);
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/catmullromspline.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 3/07/00 9:51a $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef CATMULLROMSPLINE_H
|
||||
#define CATMULLROMSPLINE_H
|
||||
|
||||
#include "hermitespline.h"
|
||||
|
||||
/**
|
||||
** CatmullRomSpline3DClass
|
||||
** This is is an implementation of 3D catmull-rom splines
|
||||
*/
|
||||
class CatmullRomSpline3DClass : public HermiteSpline3DClass
|
||||
{
|
||||
public:
|
||||
void Update_Tangents(void);
|
||||
|
||||
// save-load support
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** CatmullRomSpline1DClass
|
||||
** This is is an implementation of 1D catmull-rom splines
|
||||
*/
|
||||
class CatmullRomSpline1DClass : public HermiteSpline1DClass
|
||||
{
|
||||
public:
|
||||
void Update_Tangents(void);
|
||||
|
||||
// save-load support
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
};
|
||||
|
||||
#endif
|
||||
68
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmath.cpp
Normal file
68
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmath.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmath.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 3/16/00 2:19p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "colmath.h"
|
||||
|
||||
const float CollisionMath::COINCIDENCE_EPSILON = 0.000001f;
|
||||
CollisionMath::ColmathStatsStruct CollisionMath::Stats;
|
||||
|
||||
CollisionMath::ColmathStatsStruct::ColmathStatsStruct(void)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void CollisionMath::ColmathStatsStruct::Reset(void)
|
||||
{
|
||||
TotalCollisionCount = 0;
|
||||
TotalCollisionHitCount = 0;
|
||||
|
||||
CollisionRayTriCount = 0;
|
||||
CollisionRayTriHitCount = 0;
|
||||
|
||||
CollisionAABoxTriCount = 0;
|
||||
CollisionAABoxTriHitCount = 0;
|
||||
CollisionAABoxAABoxCount = 0;
|
||||
CollisionAABoxAABoxHitCount = 0;
|
||||
|
||||
CollisionOBBoxTriCount = 0;
|
||||
CollisionOBBoxTriHitCount = 0;
|
||||
CollisionOBBoxAABoxCount = 0;
|
||||
CollisionOBBoxAABoxHitCount = 0;
|
||||
CollisionOBBoxOBBoxCount = 0;
|
||||
CollisionOBBoxOBBoxHitCount = 0;
|
||||
}
|
||||
|
||||
312
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmath.h
Normal file
312
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmath.h
Normal file
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmath.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 5/04/01 8:25p $*
|
||||
* *
|
||||
* $Revision:: 19 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef COLMATH_H
|
||||
#define COLMATH_H
|
||||
|
||||
#ifndef ALWAYS_H
|
||||
#include "always.h"
|
||||
#endif
|
||||
|
||||
#ifndef VECTOR3_H
|
||||
#include "vector3.h"
|
||||
#endif
|
||||
|
||||
#ifndef CASTRES_H
|
||||
#include "castres.h"
|
||||
#endif
|
||||
|
||||
class AAPlaneClass;
|
||||
class PlaneClass;
|
||||
class LineSegClass;
|
||||
class TriClass;
|
||||
class SphereClass;
|
||||
class AABoxClass;
|
||||
class OBBoxClass;
|
||||
class FrustumClass;
|
||||
|
||||
const float COLLISION_EPSILON = 0.001f;
|
||||
|
||||
/*
|
||||
** #define COLMATH_STAT_TRACKING to enable stat tracking for the collision math functions
|
||||
*/
|
||||
#ifdef WWDEBUG
|
||||
#define COLMATH_STAT_TRACKING
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
** CollisionMath
|
||||
** This is a collection of the low-level math functions for collision detection.
|
||||
*/
|
||||
class CollisionMath
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Intersect Functions.
|
||||
// These functions simply return a bool indicating whether the two operands intersect.
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
static bool Intersection_Test(const AABoxClass & box,const TriClass & tri);
|
||||
static bool Intersection_Test(const AABoxClass & box,const AABoxClass & box2);
|
||||
static bool Intersection_Test(const AABoxClass & box,const OBBoxClass & box2);
|
||||
static bool Intersection_Test(const OBBoxClass & box,const TriClass & tri);
|
||||
static bool Intersection_Test(const OBBoxClass & box,const AABoxClass & box2);
|
||||
static bool Intersection_Test(const OBBoxClass & box,const OBBoxClass & box2);
|
||||
static bool Intersection_Test(const SphereClass & sphere,const AABoxClass & box);
|
||||
static bool Intersection_Test(const SphereClass & sphere,const OBBoxClass & box);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Overlap Functions.
|
||||
// Classify the second operand with respect to the first operand.
|
||||
// For example Overlap_Test(plane,point) tests whether 'point' is in front of or
|
||||
// behind 'plane'.
|
||||
// OverlapType: This enumeration is the result of an overlap test.
|
||||
// It indicates whether the the object is in the positive (front/outside) space
|
||||
// of the volume, the negative (back/inside) space of the volume, or both (overlapping)
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
enum OverlapType
|
||||
{
|
||||
POS = 0x01,
|
||||
NEG = 0x02,
|
||||
ON = 0x04,
|
||||
BOTH = 0x08,
|
||||
OUTSIDE = POS,
|
||||
INSIDE = NEG,
|
||||
OVERLAPPED = BOTH,
|
||||
FRONT = POS,
|
||||
BACK = NEG
|
||||
};
|
||||
|
||||
// AAPlane functions. Where is operand B with respect to this AAPlane
|
||||
static OverlapType Overlap_Test(const AAPlaneClass & plane,const Vector3 & point);
|
||||
static OverlapType Overlap_Test(const AAPlaneClass & plane,const LineSegClass & line);
|
||||
static OverlapType Overlap_Test(const AAPlaneClass & plane,const TriClass & tri);
|
||||
static OverlapType Overlap_Test(const AAPlaneClass & plane,const SphereClass & sphere);
|
||||
static OverlapType Overlap_Test(const AAPlaneClass & plane,const AABoxClass & box);
|
||||
static OverlapType Overlap_Test(const AAPlaneClass & plane,const OBBoxClass & box);
|
||||
|
||||
// Plane functions. Where is operand B with respect to the plane
|
||||
static OverlapType Overlap_Test(const PlaneClass & plane,const Vector3 & point);
|
||||
static OverlapType Overlap_Test(const PlaneClass & plane,const LineSegClass & line);
|
||||
static OverlapType Overlap_Test(const PlaneClass & plane,const TriClass & tri);
|
||||
static OverlapType Overlap_Test(const PlaneClass & plane,const SphereClass & sphere);
|
||||
static OverlapType Overlap_Test(const PlaneClass & plane,const Vector3 & center,const Vector3 & extent);
|
||||
inline static OverlapType Overlap_Test(const PlaneClass & plane,const AABoxClass & box);
|
||||
static OverlapType Overlap_Test(const PlaneClass & plane,const OBBoxClass & box);
|
||||
|
||||
// Sphere functions. Where is operand B with respect to the sphere
|
||||
static OverlapType Overlap_Test(const SphereClass & sphere,const Vector3 & point);
|
||||
static OverlapType Overlap_Test(const SphereClass & sphere,const LineSegClass & line);
|
||||
static OverlapType Overlap_Test(const SphereClass & sphere,const TriClass & tri);
|
||||
static OverlapType Overlap_Test(const SphereClass & sphere,const SphereClass & sphere2);
|
||||
static OverlapType Overlap_Test(const SphereClass & sphere,const AABoxClass & aabox);
|
||||
static OverlapType Overlap_Test(const SphereClass & sphere,const OBBoxClass & obbox);
|
||||
|
||||
// AABox functions. Where is operand B with respect to the AABox
|
||||
static OverlapType Overlap_Test(const AABoxClass & box,const Vector3 & point);
|
||||
static OverlapType Overlap_Test(const AABoxClass & box,const LineSegClass & line);
|
||||
static OverlapType Overlap_Test(const AABoxClass & box,const TriClass & tri);
|
||||
static OverlapType Overlap_Test(const AABoxClass & box,const AABoxClass & box2);
|
||||
static OverlapType Overlap_Test(const AABoxClass & box,const OBBoxClass & obbox);
|
||||
static OverlapType Overlap_Test(const AABoxClass & box,const SphereClass & sphere);
|
||||
|
||||
// OBBox functions, where is operand B with respect to the OBBox
|
||||
static OverlapType Overlap_Test(const OBBoxClass & box,const Vector3 & point);
|
||||
static OverlapType Overlap_Test(const OBBoxClass & box,const LineSegClass & line);
|
||||
static OverlapType Overlap_Test(const OBBoxClass & box,const TriClass & tri);
|
||||
static OverlapType Overlap_Test(const OBBoxClass & box,const AABoxClass & box2);
|
||||
static OverlapType Overlap_Test(const OBBoxClass & box,const OBBoxClass & box2);
|
||||
|
||||
// Frustum functions
|
||||
static OverlapType Overlap_Test(const FrustumClass & frustum,const Vector3 & point);
|
||||
static OverlapType Overlap_Test(const FrustumClass & frustum,const TriClass & tri);
|
||||
static OverlapType Overlap_Test(const FrustumClass & frustum,const SphereClass & sphere);
|
||||
static OverlapType Overlap_Test(const FrustumClass & frustum,const AABoxClass & box);
|
||||
static OverlapType Overlap_Test(const FrustumClass & frustum,const OBBoxClass & box);
|
||||
|
||||
// Frustum functions for hierachical culling systems.
|
||||
// At your root node, just pass in planes_passed = 0, then the variable will be modified to
|
||||
// indicate which planes that volume was inside. You can then pass that value in for the
|
||||
// test of all child nodes and optimize away some of the tests. See AABTreeCullSystemClass
|
||||
// for an example usage.
|
||||
static OverlapType Overlap_Test(const FrustumClass & frustum,const AABoxClass & box,int & planes_passed);
|
||||
static OverlapType Overlap_Test(const FrustumClass & frustum,const OBBoxClass & box,int & planes_passed);
|
||||
|
||||
// Miscellaneous other Overlap tests
|
||||
static OverlapType Overlap_Test(const Vector3 & min,const Vector3 & max,const LineSegClass & line);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Collision Functions.
|
||||
// Collide the first operand into the last operand.
|
||||
// For example Collide(box,move,tri) tests for collision between a box moving into
|
||||
// a triangle.
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Line segment functions. Intersect this line segment with the given object
|
||||
static bool Collide(const LineSegClass & line,const AAPlaneClass & plane,CastResultStruct * result);
|
||||
static bool Collide(const LineSegClass & line,const PlaneClass & plane,CastResultStruct * result);
|
||||
static bool Collide(const LineSegClass & line,const TriClass & tri,CastResultStruct * result);
|
||||
static bool Collide(const LineSegClass & line,const SphereClass & sphere,CastResultStruct * result);
|
||||
static bool Collide(const LineSegClass & line,const AABoxClass & box,CastResultStruct * result);
|
||||
static bool Collide(const LineSegClass & line,const OBBoxClass & box,CastResultStruct * result);
|
||||
|
||||
// AABox functions
|
||||
static bool Collide(const AABoxClass & box,const Vector3 & move,const PlaneClass & plane,CastResultStruct * result);
|
||||
static bool Collide(const AABoxClass & box,const Vector3 & move,const TriClass & tri,CastResultStruct * result);
|
||||
static bool Collide(const AABoxClass & box,const Vector3 & move,const AABoxClass & box2,CastResultStruct * result);
|
||||
static bool Collide(const AABoxClass & box,const Vector3 & move,const OBBoxClass & box2,const Vector3 & move2,CastResultStruct * result);
|
||||
|
||||
// OBBox functions
|
||||
static bool Collide(const OBBoxClass & box,const Vector3 & move,const PlaneClass & plane,CastResultStruct * result);
|
||||
static bool Collide(const OBBoxClass & box,const Vector3 & move,const TriClass & tri,const Vector3 & move2,CastResultStruct * result);
|
||||
static bool Collide(const OBBoxClass & box,const Vector3 & move,const AABoxClass & box2,const Vector3 & move2,CastResultStruct * result);
|
||||
static bool Collide(const OBBoxClass & box,const Vector3 & move,const OBBoxClass & box2,const Vector3 & move2,CastResultStruct * result);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Stats
|
||||
// Note that these functions will only work if you have stat tracking enabled
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct ColmathStatsStruct
|
||||
{
|
||||
ColmathStatsStruct(void);
|
||||
void Reset(void);
|
||||
|
||||
int TotalCollisionCount;
|
||||
int TotalCollisionHitCount;
|
||||
|
||||
int CollisionRayTriCount;
|
||||
int CollisionRayTriHitCount;
|
||||
|
||||
int CollisionAABoxTriCount;
|
||||
int CollisionAABoxTriHitCount;
|
||||
int CollisionAABoxAABoxCount;
|
||||
int CollisionAABoxAABoxHitCount;
|
||||
|
||||
int CollisionOBBoxTriCount;
|
||||
int CollisionOBBoxTriHitCount;
|
||||
int CollisionOBBoxAABoxCount;
|
||||
int CollisionOBBoxAABoxHitCount;
|
||||
int CollisionOBBoxOBBoxCount;
|
||||
int CollisionOBBoxOBBoxHitCount;
|
||||
};
|
||||
|
||||
static void Reset_Stats(void) { Stats.Reset(); }
|
||||
static const ColmathStatsStruct & Get_Current_Stats(void) { return Stats; }
|
||||
|
||||
private:
|
||||
|
||||
static OverlapType eval_overlap_mask(int mask);
|
||||
static OverlapType eval_overlap_collision(const CastResultStruct & res);
|
||||
|
||||
static const float COINCIDENCE_EPSILON;
|
||||
|
||||
static ColmathStatsStruct Stats;
|
||||
};
|
||||
|
||||
|
||||
inline CollisionMath::OverlapType CollisionMath::eval_overlap_mask(int mask)
|
||||
{
|
||||
// check if all verts are "ON"
|
||||
if (mask == ON) {
|
||||
return ON;
|
||||
}
|
||||
|
||||
// check if all verts are either "ON" or "POS"
|
||||
if ((mask & ~(POS | ON)) == 0) {
|
||||
return POS;
|
||||
}
|
||||
|
||||
// check if all verts are either "ON" or "BACK"
|
||||
if ((mask & ~(NEG | ON)) == 0) {
|
||||
return NEG;
|
||||
}
|
||||
|
||||
// otherwise, poly spans the plane.
|
||||
return BOTH;
|
||||
}
|
||||
|
||||
|
||||
inline CollisionMath::OverlapType CollisionMath::eval_overlap_collision(const CastResultStruct & res)
|
||||
{
|
||||
if (res.Fraction < 1.0f) {
|
||||
return BOTH;
|
||||
} else {
|
||||
if (res.StartBad) {
|
||||
return NEG;
|
||||
} else {
|
||||
return POS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Stat tracking Macros
|
||||
*/
|
||||
#ifdef COLMATH_STAT_TRACKING
|
||||
#define TRACK_COLLISION_RAY_TRI Stats.CollisionRayTriCount++; Stats.TotalCollisionCount++;
|
||||
#define TRACK_COLLISION_RAY_TRI_HIT Stats.CollisionRayTriHitCount++; Stats.TotalCollisionHitCount;
|
||||
#define TRACK_COLLISION_AABOX_TRI Stats.CollisionAABoxTriCount++; Stats.TotalCollisionCount++;
|
||||
#define TRACK_COLLISION_AABOX_TRI_HIT Stats.CollisionAABoxTriHitCount++; Stats.TotalCollisionHitCount++;
|
||||
#define TRACK_COLLISION_AABOX_AABOX Stats.CollisionAABoxAABoxCount++; Stats.TotalCollisionCount++;
|
||||
#define TRACK_COLLISION_AABOX_AABOX_HIT Stats.CollisionAABoxAABoxHitCount++; Stats.TotalCollisionHitCount++;
|
||||
#define TRACK_COLLISION_OBBOX_TRI Stats.CollisionOBBoxTriCount++; Stats.TotalCollisionCount++;
|
||||
#define TRACK_COLLISION_OBBOX_TRI_HIT Stats.CollisionOBBoxTriHitCount++; Stats.TotalCollisionHitCount++;
|
||||
#define TRACK_COLLISION_OBBOX_AABOX Stats.CollisionOBBoxAABoxCount++; Stats.TotalCollisionCount++;
|
||||
#define TRACK_COLLISION_OBBOX_AABOX_HIT Stats.CollisionOBBoxAABoxHitCount++; Stats.TotalCollisionHitCount++;
|
||||
#define TRACK_COLLISION_OBBOX_OBBOX Stats.CollisionOBBoxOBBoxCount++; Stats.TotalCollisionCount++;
|
||||
#define TRACK_COLLISION_OBBOX_OBBOX_HIT Stats.CollisionOBBoxOBBoxHitCount++; Stats.TotalCollisionHitCount++;
|
||||
#else
|
||||
#define TRACK_COLLISION_RAY_TRI
|
||||
#define TRACK_COLLISION_RAY_TRI_HIT
|
||||
#define TRACK_COLLISION_AABOX_TRI
|
||||
#define TRACK_COLLISION_AABOX_TRI_HIT
|
||||
#define TRACK_COLLISION_AABOX_AABOX
|
||||
#define TRACK_COLLISION_AABOX_AABOX_HIT
|
||||
#define TRACK_COLLISION_OBBOX_TRI
|
||||
#define TRACK_COLLISION_OBBOX_TRI_HIT
|
||||
#define TRACK_COLLISION_OBBOX_AABOX
|
||||
#define TRACK_COLLISION_OBBOX_AABOX_HIT
|
||||
#define TRACK_COLLISION_OBBOX_OBBOX
|
||||
#define TRACK_COLLISION_OBBOX_OBBOX_HIT
|
||||
#endif
|
||||
|
||||
#endif // COLMATH_H
|
||||
596
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabox.cpp
Normal file
596
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabox.cpp
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathaabox.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 8/30/01 7:40p $*
|
||||
* *
|
||||
* $Revision:: 22 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* CollisionMath::Intersection_Test -- Test intersection between two AABoxes *
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between an AABox and a sphere *
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between an AABox and a triangle *
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between an AABox and a line segment *
|
||||
* CollisionMath::Collide -- Collision test for a moving AABox and a plane *
|
||||
* aab_separation_test -- tests two AAB's for separation on an axis *
|
||||
* CollisionMath::Collide -- Collision test for two moving AABoxes *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "colmath.h"
|
||||
#include "colmathinlines.h"
|
||||
#include "aaplane.h"
|
||||
#include "plane.h"
|
||||
#include "lineseg.h"
|
||||
#include "tri.h"
|
||||
#include "sphere.h"
|
||||
#include "aabox.h"
|
||||
#include "obbox.h"
|
||||
#include "wwdebug.h"
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Intersection_Test -- Test intersection between two AABoxes *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/19/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CollisionMath::Intersection_Test(const AABoxClass & box,const AABoxClass & box2)
|
||||
{
|
||||
Vector3 dc = box2.Center - box.Center;
|
||||
|
||||
if (box.Extent.X + box2.Extent.X < WWMath::Fabs(dc.X)) return false;
|
||||
if (box.Extent.Y + box2.Extent.Y < WWMath::Fabs(dc.Y)) return false;
|
||||
if (box.Extent.Z + box2.Extent.Z < WWMath::Fabs(dc.Z)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between an AABox and a sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/19/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const SphereClass & sphere)
|
||||
{
|
||||
// TODO: this function seems incorrect. Not currently using it though
|
||||
Vector3 dist = sphere.Center - box.Center;
|
||||
|
||||
Vector3 extent;
|
||||
extent.X = box.Extent.X + sphere.Radius;
|
||||
extent.Y = box.Extent.Y + sphere.Radius;
|
||||
extent.Z = box.Extent.Z + sphere.Radius;
|
||||
|
||||
//
|
||||
// Check to see if the sphere is completely outside the box
|
||||
//
|
||||
if (WWMath::Fabs(dist.X) > extent.X) return OUTSIDE;
|
||||
if (WWMath::Fabs(dist.Y) > extent.Y) return OUTSIDE;
|
||||
if (WWMath::Fabs(dist.Z) > extent.Z) return OUTSIDE;
|
||||
|
||||
return INSIDE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between an AABox and a line segment *
|
||||
* *
|
||||
* This function uses separating axes to determine whether an AABox and a line segment overlap *
|
||||
* I wrote it when we found that ray-casting was taking a huge amount of time in Renegade. *
|
||||
* Here are some statistics comparing this function to the previous function which used the *
|
||||
* same algorithm that Collide(box,ray) uses. *
|
||||
* *
|
||||
* collide algorithm (Gems) separating axis (this one) *
|
||||
* ----------------------------------------------------------------------------------------- *
|
||||
* number of tests 10000 10000 *
|
||||
* avg cycles 641 464 *
|
||||
* outside cycles 652 390 *
|
||||
* overlap cycles 610 683 *
|
||||
* *
|
||||
* The idea for this test is that it will early-exit when it can while the old test can't. *
|
||||
* When we are passing a ray down our culling trees, it is common to encounter boxes that *
|
||||
* are not intersecting the ray. The faster we can reject these, the better! *
|
||||
* *
|
||||
* INPUT: *
|
||||
* box - box to test *
|
||||
* line - line to test *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* overlap status of the line with respect to the box, either INSIDE, OUTSIDE, or OVERLAPPED *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/19/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const LineSegClass & line)
|
||||
{
|
||||
// If both endpoints are in, return INSIDE
|
||||
// If either was inside, return OVERLAPPED
|
||||
int inside_point_count = 0;
|
||||
if (CollisionMath::Overlap_Test(box,line.Get_P0()) == INSIDE) inside_point_count++;
|
||||
if (CollisionMath::Overlap_Test(box,line.Get_P1()) == INSIDE) inside_point_count++;
|
||||
|
||||
if (inside_point_count == 2) {
|
||||
|
||||
return INSIDE;
|
||||
|
||||
} else if (inside_point_count == 1) {
|
||||
|
||||
return OVERLAPPED;
|
||||
|
||||
} else {
|
||||
|
||||
// Here I'm using the separating axis theorem to test if the line-segment
|
||||
// and the box can be separated by a plane. Any two convex objects that are
|
||||
// not intersecting can be separated by a plane defined by either a
|
||||
// face normal from one of the objects or the cross-product of an edge from
|
||||
// each object. In the case of an axis-aligned box and a line-segment, we
|
||||
// have to check the three coordinate axes and the cross product between
|
||||
// each and the direction vector of the line segment.
|
||||
//
|
||||
// Here is the general test for an arbitrary axis:
|
||||
// -----------------------------------------------
|
||||
// box_proj = fabs(extent.X*axis.X) + fabs(extent.Y*axis.Y) + fabs(extent.Z*axis.Z)
|
||||
// p0_proj = fabs(dot_product(dp0,axis))
|
||||
// dp_proj = fabs(dot_product(dp,axis))
|
||||
// if (p0_proj > 0) {
|
||||
// if (p0_proj > box_proj - WWMath::Min(dp_proj,0.0f)) return OUTSIDE;
|
||||
// } else {
|
||||
// if (-p0_proj > box_proj + WWMath::Max(dp_proj,0.0f)) return OUTSIDE;
|
||||
// }
|
||||
//
|
||||
// In practice, there are optimizations you can make on each of the axes that
|
||||
// we need to test (see below).
|
||||
|
||||
float box_proj,p0_proj,dp_proj;
|
||||
Vector3 dp0;
|
||||
Vector3::Subtract(line.Get_P0(),box.Center,&dp0);
|
||||
|
||||
// Project box and line onto the x-axis
|
||||
// Since I know the axis is the x-axis, just take the x components of each
|
||||
// vector instead of doing the dot-product. The projection of 'dp' is only
|
||||
// counted if it points towards the center of the box (i.e. it decreases the
|
||||
// chances of them being separated...)
|
||||
box_proj = box.Extent.X;
|
||||
p0_proj = dp0.X;
|
||||
dp_proj = line.Get_DP().X;
|
||||
if (p0_proj > 0) {
|
||||
if (p0_proj > box_proj - WWMath::Min(dp_proj,0.0f)) return OUTSIDE;
|
||||
} else {
|
||||
if (-p0_proj > box_proj + WWMath::Max(dp_proj,0.0f)) return OUTSIDE;
|
||||
}
|
||||
|
||||
// Project box and line onto the y-axis
|
||||
box_proj = box.Extent.Y;
|
||||
p0_proj = dp0.Y;
|
||||
dp_proj = line.Get_DP().Y;
|
||||
if (p0_proj > 0) {
|
||||
if (p0_proj > box_proj - WWMath::Min(dp_proj,0.0f)) return OUTSIDE;
|
||||
} else {
|
||||
if (-p0_proj > box_proj + WWMath::Max(dp_proj,0.0f)) return OUTSIDE;
|
||||
}
|
||||
|
||||
// Project box and line onto the z-axis
|
||||
box_proj = box.Extent.Z;
|
||||
p0_proj = dp0.Z;
|
||||
dp_proj = line.Get_DP().Z;
|
||||
if (p0_proj > 0) {
|
||||
if (p0_proj > box_proj - WWMath::Min(dp_proj,0.0f)) return OUTSIDE;
|
||||
} else {
|
||||
if (-p0_proj > box_proj + WWMath::Max(dp_proj,0.0f)) return OUTSIDE;
|
||||
}
|
||||
|
||||
// Project box and line onto (x cross line)
|
||||
// I'm manually optimizing the cross-product and taking advantage of the fact
|
||||
// that 'dp' will always project to zero for this axis.
|
||||
Vector3 axis;
|
||||
axis.Set(0,-line.Get_Dir().Z,line.Get_Dir().Y); // == (1,0,0) cross (x,y,z)
|
||||
box_proj = WWMath::Fabs(axis.Y*box.Extent.Y) + WWMath::Fabs(axis.Z*box.Extent.Z);
|
||||
p0_proj = Vector3::Dot_Product(axis,dp0);
|
||||
if (WWMath::Fabs(p0_proj) > box_proj) return OUTSIDE;
|
||||
|
||||
// Project box and line onto (y cross line)
|
||||
axis.Set(line.Get_Dir().Z,0,-line.Get_Dir().X); // == (0,1,0) cross (x,y,z)
|
||||
box_proj = WWMath::Fabs(axis.X*box.Extent.X) + WWMath::Fabs(axis.Z*box.Extent.Z);
|
||||
p0_proj = Vector3::Dot_Product(axis,dp0);
|
||||
if (WWMath::Fabs(p0_proj) > box_proj) return OUTSIDE;
|
||||
|
||||
// Project box and line onto (z cross line)
|
||||
axis.Set(-line.Get_Dir().Y,line.Get_Dir().X,0); // == (0,0,1) cross (x,y,z)
|
||||
box_proj = WWMath::Fabs(axis.X*box.Extent.X) + WWMath::Fabs(axis.Y*box.Extent.Y);
|
||||
p0_proj = Vector3::Dot_Product(axis,dp0);
|
||||
if (WWMath::Fabs(p0_proj) > box_proj) return OUTSIDE;
|
||||
|
||||
}
|
||||
return OVERLAPPED;
|
||||
}
|
||||
|
||||
#if 0 // Alternate Overlap Test for AABox-Ray
|
||||
CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const LineSegClass & line)
|
||||
{
|
||||
// If both endpoints are in, return INSIDE
|
||||
// If either was inside, return OVERLAPPED
|
||||
int inside_point_count = 0;
|
||||
if (CollisionMath::Overlap_Test(box,line.Get_P0()) == INSIDE) inside_point_count++;
|
||||
if (CollisionMath::Overlap_Test(box,line.Get_P1()) == INSIDE) inside_point_count++;
|
||||
|
||||
if (inside_point_count == 2) {
|
||||
|
||||
return INSIDE;
|
||||
|
||||
} else if (inside_point_count == 1) {
|
||||
|
||||
return OVERLAPPED;
|
||||
|
||||
} else {
|
||||
|
||||
// Now we know that both points are outside of the box so we
|
||||
// have to detect if the ray penetrates the box.
|
||||
// I found this algorithm in one of the GEMS books...
|
||||
Vector3 boxmin,boxmax;
|
||||
Vector3::Subtract(box.Center,box.Extent,&boxmin);
|
||||
Vector3::Add(box.Center,box.Extent,&boxmax);
|
||||
|
||||
float candidateplane[3]; // candidate intersection plane distance for each axis
|
||||
float maxt[3]; // t value along the ray for each axis
|
||||
Vector3 coord; // intersection point
|
||||
|
||||
const int BOX_SIDE_NEGATIVE = -1;
|
||||
const int BOX_SIDE_MIDDLE = 0;
|
||||
const int BOX_SIDE_POSITIVE = 1;
|
||||
|
||||
int quadrant[3];
|
||||
for (int i=0; i<3; i++) {
|
||||
if (line.Get_P0()[i] < boxmin[i]) {
|
||||
quadrant[i] = BOX_SIDE_NEGATIVE;
|
||||
candidateplane[i] = boxmin[i];
|
||||
} else if (line.Get_P0()[i] > boxmax[i]) {
|
||||
quadrant[i] = BOX_SIDE_POSITIVE;
|
||||
candidateplane[i] = boxmax[i];
|
||||
} else {
|
||||
quadrant[i] = BOX_SIDE_MIDDLE;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the 3 distances to the candidate planes
|
||||
for (i=0; i<3; i++) {
|
||||
if (quadrant[i] != BOX_SIDE_MIDDLE && line.Get_DP()[i] != 0.0f) {
|
||||
maxt[i] = (candidateplane[i] - line.Get_P0()[i]) / line.Get_DP()[i];
|
||||
} else {
|
||||
maxt[i] = -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the largest of the maxt's for the final choice of intersection
|
||||
int intersection_plane = 0;
|
||||
for (i=1; i<3; i++) {
|
||||
if (maxt[i] > maxt[intersection_plane]) {
|
||||
intersection_plane = i;
|
||||
}
|
||||
}
|
||||
|
||||
// If the ray is "in front" of all of the planes, return
|
||||
if (maxt[intersection_plane] < 0.0f) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
|
||||
// If the intersection is beyond the end of the ray, return
|
||||
if (maxt[intersection_plane] > 1.0f) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
|
||||
// Check if the ray is inside the box, i.e. on the two planes which
|
||||
// are not the intersection planes, the intersection point should
|
||||
// be between the min and max of the box.
|
||||
for (i=0; i<3; i++) {
|
||||
|
||||
if (intersection_plane != i) {
|
||||
|
||||
coord[i] = line.Get_P0()[i] + maxt[intersection_plane] * line.Get_DP()[i];
|
||||
if ((coord[i] < boxmin[i]) || (coord[i] > boxmax[i])) {
|
||||
return OUTSIDE; // ray is outside the box
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
coord[i] = candidateplane[i];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return OVERLAPPED;
|
||||
}
|
||||
#endif // Alternate Overlap Test for AABox-Ray
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between an AABox and a triangle *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/19/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const TriClass & tri)
|
||||
{
|
||||
CastResultStruct res;
|
||||
CollisionMath::Collide(box,Vector3(0,0,0),tri,&res);
|
||||
return eval_overlap_collision(res);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Collide -- Collision test for a moving AABox and a plane *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/19/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CollisionMath::Collide
|
||||
(
|
||||
const AABoxClass & box,
|
||||
const Vector3 & move_vector,
|
||||
const PlaneClass & plane,
|
||||
CastResultStruct * result
|
||||
)
|
||||
{
|
||||
float frac;
|
||||
|
||||
float extent = box.Project_To_Axis(plane.N);
|
||||
float dist = Vector3::Dot_Product(plane.N,box.Center) + plane.D;
|
||||
float move = Vector3::Dot_Product(plane.N,move_vector);
|
||||
|
||||
if (dist > extent) {
|
||||
if (dist + move > extent) {
|
||||
// entire move ok!
|
||||
frac = 1.0f;
|
||||
} else {
|
||||
// partial move allowed
|
||||
frac = (extent - dist) / move;
|
||||
}
|
||||
|
||||
} else if (dist < -extent) {
|
||||
if (dist + move < -extent) {
|
||||
// entire move ok!
|
||||
frac = 1.0f;
|
||||
} else {
|
||||
// partial move allowed
|
||||
frac = (-extent - dist) / move;
|
||||
}
|
||||
|
||||
} else {
|
||||
result->StartBad = true;
|
||||
result->Normal = plane.N;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (frac < result->Fraction) {
|
||||
result->Fraction = frac;
|
||||
result->Normal = plane.N;
|
||||
if (result->ComputeContactPoint) {
|
||||
Vector3 move_dir(move_vector);
|
||||
move_dir.Normalize();
|
||||
float move_extent = Vector3::Dot_Product(box.Extent,move_dir);
|
||||
result->ContactPoint = box.Center + result->Fraction * move_vector + move_extent * move_dir;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** AABCollisionStruct
|
||||
** Contains all of the intermediate and temporary values used by
|
||||
** the set of functions used in detecting collisions for aab's
|
||||
*/
|
||||
struct AABCollisionStruct
|
||||
{
|
||||
AABCollisionStruct(const AABoxClass &box0,const Vector3 &move0,const AABoxClass & box1,const Vector3 &move1) :
|
||||
StartBad(true), // Startbad is true until one of the axes clears it
|
||||
AxisId(-1), // AxisId will be the axis that allowed the longest move
|
||||
MaxFrac(0.0f), // MaxFrac is the longest allowed move so far
|
||||
Box0(box0),
|
||||
Box1(box1)
|
||||
{
|
||||
Vector3::Subtract(box1.Center,box0.Center,&C); // vector from center of box0 to center of box1
|
||||
Vector3::Subtract(move1,move0,&M); // move vector relative to stationary box0
|
||||
}
|
||||
|
||||
bool StartBad; // Inital configuration is intersecting?
|
||||
float MaxFrac; // Longest move allowed so far
|
||||
int AxisId; // Last separating axis
|
||||
int Side; // which side of the interval
|
||||
|
||||
Vector3 C; // Vector from the center0 to center1
|
||||
Vector3 M; // Move vector relative to stationary box0
|
||||
|
||||
const AABoxClass & Box0;
|
||||
const AABoxClass & Box1;
|
||||
|
||||
private:
|
||||
|
||||
//not implemented
|
||||
AABCollisionStruct(const AABCollisionStruct&);
|
||||
AABCollisionStruct & operator = (const AABCollisionStruct&);
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* aab_separation_test -- tests two AAB's for separation on an axis *
|
||||
* *
|
||||
* This function is very similar to the obb_separation_test. If a flaw is found in either, *
|
||||
* we should update the other... *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/19/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
static inline bool aab_separation_test
|
||||
(
|
||||
AABCollisionStruct & context,
|
||||
int axis
|
||||
)
|
||||
{
|
||||
// ra = box0 projection onto the axis
|
||||
// rb = box1 projection onto the axis
|
||||
// u0 = projected distance between the box centers at t0
|
||||
// u1 = projected distance between the box centers at t1
|
||||
float ra = context.Box0.Extent[axis];
|
||||
float rb = context.Box1.Extent[axis];
|
||||
float u0 = context.C[axis];
|
||||
float u1 = u0 + context.M[axis];
|
||||
|
||||
float tmp;
|
||||
float rsum = ra+rb;
|
||||
|
||||
if ( u0 + WWMATH_EPSILON > rsum ) {
|
||||
context.StartBad = false;
|
||||
if ( u1 > rsum ) {
|
||||
context.MaxFrac = 1.0f;
|
||||
return true;
|
||||
} else {
|
||||
tmp = (rsum-u0)/(u1-u0);
|
||||
if ( tmp > context.MaxFrac ) {
|
||||
context.MaxFrac = tmp;
|
||||
context.AxisId = axis;
|
||||
context.Side = +1;
|
||||
}
|
||||
}
|
||||
} else if ( u0 - WWMATH_EPSILON < -rsum ) {
|
||||
context.StartBad = false;
|
||||
if ( u1 < -rsum ) {
|
||||
context.MaxFrac = 1.0f;
|
||||
return true;
|
||||
} else {
|
||||
tmp = (-rsum-u0)/(u1-u0);
|
||||
if ( tmp > context.MaxFrac ) {
|
||||
context.MaxFrac = tmp;
|
||||
context.AxisId = axis;
|
||||
context.Side = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Collide -- Collision test for two moving AABoxes *
|
||||
* *
|
||||
* this function sweeps two AABoxes and finds the first time of collision. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* currently there is no parateter for the movement of the second box. the internal code *
|
||||
* can handle it though. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/19/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CollisionMath::Collide(const AABoxClass & box,const Vector3 & move,const AABoxClass & box2,CastResultStruct * result)
|
||||
{
|
||||
/*
|
||||
** Test the X-axis
|
||||
** ra = box projection onto the axis
|
||||
** rb = box2 projection onto the axis
|
||||
** u0 = projected distance between the box centers at t0
|
||||
** u1 = projected distance between the box centers at t1
|
||||
*/
|
||||
AABCollisionStruct context(box,move,box2,Vector3(0,0,0));
|
||||
|
||||
if (aab_separation_test(context,0)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (aab_separation_test(context,1)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (aab_separation_test(context,2)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
if (context.StartBad) {
|
||||
result->StartBad = true;
|
||||
result->Fraction = 0.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.MaxFrac < result->Fraction) {
|
||||
|
||||
result->Fraction = context.MaxFrac;
|
||||
result->Normal.Set(0,0,0);
|
||||
result->Normal[context.AxisId] = -context.Side;
|
||||
|
||||
if (result->ComputeContactPoint) {
|
||||
//WWASSERT(0); // TODO
|
||||
WWDEBUG_SAY(("AABox-AABox collision does not currently support contact point computation\r\n"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
110
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabox.h
Normal file
110
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabox.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathaabox.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 5/08/01 5:01p $*
|
||||
* *
|
||||
* $Revision:: 8 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* CollisionMath::Overlap_Test -- test overlap between an AABox and a point *
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between two AABoxes *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef COLMATHAABOX_H
|
||||
#define COLMATHAABOX_H
|
||||
|
||||
#include "always.h"
|
||||
#include "aabox.h"
|
||||
#include "vector3.h"
|
||||
#include "lineseg.h"
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- test overlap between an AABox and a point *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/14/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const Vector3 & point)
|
||||
{
|
||||
if (WWMath::Fabs(point.X - box.Center.X) > box.Extent.X) return POS;
|
||||
if (WWMath::Fabs(point.Y - box.Center.Y) > box.Extent.Y) return POS;
|
||||
if (WWMath::Fabs(point.Z - box.Center.Z) > box.Extent.Z) return POS;
|
||||
|
||||
return NEG;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between two AABoxes *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/19/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE CollisionMath::OverlapType CollisionMath::Overlap_Test(const AABoxClass & box,const AABoxClass & box2)
|
||||
{
|
||||
Vector3 dc;
|
||||
Vector3::Subtract(box2.Center,box.Center,&dc);
|
||||
|
||||
if (box.Extent.X + box2.Extent.X < WWMath::Fabs(dc.X)) return POS;
|
||||
if (box.Extent.Y + box2.Extent.Y < WWMath::Fabs(dc.Y)) return POS;
|
||||
if (box.Extent.Z + box2.Extent.Z < WWMath::Fabs(dc.Z)) return POS;
|
||||
|
||||
if ( (dc.X + box2.Extent.X <= box.Extent.X) &&
|
||||
(dc.Y + box2.Extent.Y <= box.Extent.Y) &&
|
||||
(dc.Z + box2.Extent.Z <= box.Extent.Z) &&
|
||||
(dc.X - box2.Extent.X >= -box.Extent.X) &&
|
||||
(dc.Y - box2.Extent.Y >= -box.Extent.Y) &&
|
||||
(dc.Z - box2.Extent.Z >= -box.Extent.Z))
|
||||
{
|
||||
return NEG; // inside;
|
||||
}
|
||||
|
||||
return BOTH;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
1184
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp
Normal file
1184
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathaabtri.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathfrustum.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 3/29/00 5:40p $*
|
||||
* *
|
||||
* $Revision:: 7 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "colmath.h"
|
||||
#include "colmathinlines.h"
|
||||
#include "aaplane.h"
|
||||
#include "plane.h"
|
||||
#include "lineseg.h"
|
||||
#include "tri.h"
|
||||
#include "sphere.h"
|
||||
#include "aabox.h"
|
||||
#include "obbox.h"
|
||||
#include "frustum.h"
|
||||
#include "wwdebug.h"
|
||||
|
||||
|
||||
// TODO: Most of these overlap functions actually do not catch all cases of when
|
||||
// the primitive is outside of the frustum...
|
||||
|
||||
|
||||
// Frustum functions
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const FrustumClass & frustum,const Vector3 & point)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int result = CollisionMath::Overlap_Test(frustum.Planes[i],point);
|
||||
if (result == OUTSIDE) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
mask |= result;
|
||||
}
|
||||
|
||||
if (mask == INSIDE) {
|
||||
return INSIDE;
|
||||
}
|
||||
return OVERLAPPED;
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const FrustumClass & frustum,const TriClass & tri)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
// TODO: doesn't catch all cases...
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int result = CollisionMath::Overlap_Test(frustum.Planes[i],tri);
|
||||
if (result == OUTSIDE) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
mask |= result;
|
||||
}
|
||||
|
||||
if (mask == INSIDE) {
|
||||
return INSIDE;
|
||||
}
|
||||
return OVERLAPPED;
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const FrustumClass & frustum,const SphereClass & sphere)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
// TODO: doesn't catch all cases...
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int result = CollisionMath::Overlap_Test(frustum.Planes[i],sphere);
|
||||
if (result == OUTSIDE) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
mask |= result;
|
||||
}
|
||||
|
||||
if (mask == INSIDE) {
|
||||
return INSIDE;
|
||||
}
|
||||
return OVERLAPPED;
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const FrustumClass & frustum,const AABoxClass & box)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
// TODO: doesn't catch all cases...
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int result = CollisionMath::Overlap_Test(frustum.Planes[i],box);
|
||||
if (result == OUTSIDE) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
mask |= result;
|
||||
}
|
||||
|
||||
if (mask == INSIDE) {
|
||||
return INSIDE;
|
||||
}
|
||||
return OVERLAPPED;
|
||||
}
|
||||
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const FrustumClass & frustum,const OBBoxClass & box)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
// TODO: doesn't catch all cases...
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int result = CollisionMath::Overlap_Test(frustum.Planes[i],box);
|
||||
if (result == OUTSIDE) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
mask |= result;
|
||||
}
|
||||
|
||||
if (mask == INSIDE) {
|
||||
return INSIDE;
|
||||
}
|
||||
return OVERLAPPED;
|
||||
}
|
||||
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const FrustumClass & frustum,const OBBoxClass & box,int & planes_passed)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
// TODO: doesn't catch all cases...
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
||||
int plane_bit = (1<<i);
|
||||
|
||||
// only check this plane if we have to
|
||||
if ((planes_passed & plane_bit) == 0) {
|
||||
|
||||
int result = CollisionMath::Overlap_Test(frustum.Planes[i],box);
|
||||
if (result == OUTSIDE) {
|
||||
return OUTSIDE;
|
||||
} else if (result == INSIDE) {
|
||||
planes_passed |= plane_bit;
|
||||
}
|
||||
mask |= result;
|
||||
|
||||
} else {
|
||||
|
||||
mask |= INSIDE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (mask == INSIDE) {
|
||||
return INSIDE;
|
||||
}
|
||||
return OVERLAPPED;
|
||||
}
|
||||
|
||||
105
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathfrustum.h
Normal file
105
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathfrustum.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathfrustum.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 5/04/01 8:25p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* CollisionMath::Overlap_Test -- test a frustum and an AABox for overlap *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef COLMATHFRUSTUM_H
|
||||
#define COLMATHFRUSTUM_H
|
||||
|
||||
#include "always.h"
|
||||
#include "aabox.h"
|
||||
#include "vector3.h"
|
||||
#include "lineseg.h"
|
||||
#include "frustum.h"
|
||||
|
||||
/*
|
||||
** Inline collision functions dealing with frustums
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- test a frustum and an AABox for overlap *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/29/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
inline
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const FrustumClass & frustum,const AABoxClass & box,int & planes_passed)
|
||||
{
|
||||
int mask = 0;
|
||||
|
||||
// TODO: doesn't catch all cases...
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
||||
int plane_bit = (1<<i);
|
||||
|
||||
// only check this plane if we have to
|
||||
if ((planes_passed & plane_bit) == 0) {
|
||||
|
||||
int result = CollisionMath::Overlap_Test(frustum.Planes[i],box);
|
||||
if (result == OUTSIDE) {
|
||||
|
||||
return OUTSIDE;
|
||||
} else if (result == INSIDE) {
|
||||
planes_passed |= plane_bit;
|
||||
}
|
||||
mask |= result;
|
||||
|
||||
} else {
|
||||
|
||||
mask |= INSIDE;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (mask == INSIDE) {
|
||||
return INSIDE;
|
||||
}
|
||||
return OVERLAPPED;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathinlines.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 3/29/00 5:36p $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef COLMATHINLINES_H
|
||||
#define COLMATHINLINES_H
|
||||
|
||||
#include "colmathaabox.h"
|
||||
#include "colmathfrustum.h"
|
||||
#include "colmathline.h"
|
||||
#include "colmathplane.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
484
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathline.cpp
Normal file
484
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathline.cpp
Normal file
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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:: /VSS_Sync/wwmath/colmathline.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 8/29/01 10:25p $*
|
||||
* *
|
||||
* $Revision:: 10 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "colmath.h"
|
||||
#include "aaplane.h"
|
||||
#include "plane.h"
|
||||
#include "lineseg.h"
|
||||
#include "tri.h"
|
||||
#include "sphere.h"
|
||||
#include "aabox.h"
|
||||
#include "obbox.h"
|
||||
#include "wwdebug.h"
|
||||
|
||||
|
||||
/*
|
||||
** Structure used in the line->box test. There was a lot of common code between the axis-
|
||||
** aligned and oriented box tests so I package all of the truely relevant information into
|
||||
** this struct and pass it into a function local to this module. In the case of oriented
|
||||
** boxes, the ray must be transformed into the box's coordinate system prior to the call
|
||||
** and the normal is calculated slightly differently.
|
||||
*/
|
||||
struct BoxTestStruct
|
||||
{
|
||||
Vector3 Min;
|
||||
Vector3 Max;
|
||||
Vector3 P0;
|
||||
Vector3 DP;
|
||||
float Fraction;
|
||||
bool Inside;
|
||||
int Axis;
|
||||
int Side;
|
||||
};
|
||||
|
||||
/*
|
||||
** Enumeration which can be used to categorize a point with respect to the projection
|
||||
** of a box onto an axis. The point will either be to the negative side of the span, in the
|
||||
** span, or on the positive side of the span.
|
||||
*/
|
||||
enum BoxSideType {
|
||||
BOX_SIDE_NEGATIVE = 0,
|
||||
BOX_SIDE_POSITIVE = 1,
|
||||
BOX_SIDE_MIDDLE = 2
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Table of normals for an axis aligned box.
|
||||
** access like this:
|
||||
**
|
||||
** _box_normal[AXIS][SIDE]
|
||||
**
|
||||
** <AXIS> is 0,1,2 meaning x,y,z
|
||||
** <SIDE> is BOX_SIDE_NEGATIVE or BOX_SIDE_POSITIVE
|
||||
*/
|
||||
static Vector3 _box_normal[3][2] =
|
||||
{
|
||||
// plane = 0 (x axis)
|
||||
{
|
||||
Vector3(-1,0,0), // Left
|
||||
Vector3(1,0,0) // Right
|
||||
},
|
||||
// plane = 1 (y axis)
|
||||
{
|
||||
Vector3(0,-1,0),
|
||||
Vector3(0,1,0)
|
||||
},
|
||||
// plane = 2 (z axis)
|
||||
{
|
||||
Vector3(0,0,-1),
|
||||
Vector3(0,0,1)
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
** Local function prototypes
|
||||
*/
|
||||
inline bool Test_Aligned_Box(BoxTestStruct * test);
|
||||
|
||||
|
||||
bool CollisionMath::Collide(const LineSegClass & line,const AAPlaneClass & plane,CastResultStruct * result)
|
||||
{
|
||||
float num,den,t;
|
||||
|
||||
den = line.Get_DP()[plane.Normal];
|
||||
|
||||
/*
|
||||
** Check if line is parallel to this plane
|
||||
*/
|
||||
if (den == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
num = -(line.Get_P0()[plane.Normal] - plane.Dist);
|
||||
t = num/den;
|
||||
|
||||
/*
|
||||
** If t is not between 0 and 1, the line containing the segment intersects
|
||||
** the plane but the segment does not
|
||||
*/
|
||||
if ((t < 0.0f) || (t > 1.0f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
** Ok, we hit the plane!
|
||||
*/
|
||||
if (t < result->Fraction) {
|
||||
result->Fraction = t;
|
||||
result->Normal.Set(0,0,0);
|
||||
result->Normal[plane.Normal] = 1.0f;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CollisionMath::Collide(const LineSegClass & line,const PlaneClass & plane,CastResultStruct * result)
|
||||
{
|
||||
float num,den,t;
|
||||
den = Vector3::Dot_Product(plane.N,line.Get_DP());
|
||||
|
||||
/*
|
||||
** If the denominator is zero, the ray is parallel to the plane
|
||||
*/
|
||||
if (den == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
num = -(Vector3::Dot_Product(plane.N,line.Get_P0()) - plane.D);
|
||||
t = num/den;
|
||||
|
||||
/*
|
||||
** If t is not between 0 and 1, the line containing the segment intersects
|
||||
** the plane but the segment does not
|
||||
*/
|
||||
if ((t < 0.0f) || (t > 1.0f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
** Ok, we hit the plane!
|
||||
*/
|
||||
if (t < result->Fraction) {
|
||||
result->Fraction = t;
|
||||
result->Normal = plane.N;
|
||||
|
||||
/*
|
||||
** if user is asking for the point, compute it.
|
||||
*/
|
||||
if (result->ComputeContactPoint) {
|
||||
result->ContactPoint = line.Get_P0() + result->Fraction * line.Get_DP();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CollisionMath::Collide(const LineSegClass & line,const TriClass & tri,CastResultStruct * res)
|
||||
{
|
||||
TRACK_COLLISION_RAY_TRI;
|
||||
|
||||
/*
|
||||
** Compute intersection of the line with the plane of the polygon
|
||||
*/
|
||||
PlaneClass plane(*tri.N,*tri.V[0]);
|
||||
Vector3 ipoint;
|
||||
float num,den,t;
|
||||
|
||||
den = Vector3::Dot_Product(plane.N,line.Get_DP());
|
||||
|
||||
/*
|
||||
** If the denominator is zero, the ray is parallel to the plane
|
||||
*/
|
||||
if (den == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
num = -(Vector3::Dot_Product(plane.N,line.Get_P0()) - plane.D);
|
||||
t = num/den;
|
||||
|
||||
/*
|
||||
** If t is not between 0 and 1, the line containing the segment intersects
|
||||
** the plane but the segment does not
|
||||
*/
|
||||
if ((t < 0.0f) || (t > 1.0f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ipoint = line.Get_P0() + t*line.Get_DP();
|
||||
|
||||
/*
|
||||
** Check if this point is inside the triangle
|
||||
*/
|
||||
if (!tri.Contains_Point(ipoint)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
** Ok, we hit the triangle, set the collision results
|
||||
*/
|
||||
if (t < res->Fraction) {
|
||||
res->Fraction = t;
|
||||
res->Normal = plane.N;
|
||||
if (res->ComputeContactPoint) {
|
||||
res->ContactPoint = line.Get_P0() + res->Fraction * line.Get_DP();
|
||||
}
|
||||
TRACK_COLLISION_RAY_TRI_HIT;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CollisionMath::Collide(const LineSegClass & line,const SphereClass & sphere,CastResultStruct * res)
|
||||
{
|
||||
// this game from graphics gems 1, page 388
|
||||
// intersection of a ray with a sphere
|
||||
Vector3 dc = sphere.Center - line.Get_P0();
|
||||
float clen = Vector3::Dot_Product((dc) , line.Get_Dir());
|
||||
float disc = (sphere.Radius * sphere.Radius) - (dc.Length2() - clen*clen);
|
||||
if (disc < 0.0f) {
|
||||
return false;
|
||||
} else {
|
||||
float d = WWMath::Sqrt(disc);
|
||||
float frac = (clen - d) / line.Get_Length();
|
||||
if (frac<0.0f)
|
||||
frac = (clen + d) / line.Get_Length();
|
||||
if (frac<0.0f) return false;
|
||||
if (frac < res->Fraction) {
|
||||
|
||||
res->Fraction = frac;
|
||||
|
||||
Vector3 p = line.Get_P0() + (clen - d)*line.Get_Dir();
|
||||
Vector3 norm = p - sphere.Center;
|
||||
norm /= sphere.Radius;
|
||||
|
||||
res->Normal = norm;
|
||||
if (res->ComputeContactPoint) {
|
||||
res->ContactPoint = line.Get_P0() + res->Fraction * line.Get_DP();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CollisionMath::Collide(const LineSegClass & line,const AABoxClass & box,CastResultStruct * res)
|
||||
{
|
||||
// set up the test struct
|
||||
BoxTestStruct test;
|
||||
test.Min = box.Center - box.Extent;
|
||||
test.Max = box.Center + box.Extent;
|
||||
test.P0 = line.Get_P0();
|
||||
test.DP = line.Get_DP();
|
||||
|
||||
// check ray against the box, exit if the ray totally missed the box,
|
||||
if (!Test_Aligned_Box(&test)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if ray starts inside the box, note that fact and bail.
|
||||
if (test.Inside) {
|
||||
res->StartBad = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now, if this intersection is before any current intersection
|
||||
// that we've found, install our intersection
|
||||
if (test.Fraction < res->Fraction) {
|
||||
res->Fraction = test.Fraction;
|
||||
assert(test.Side != BOX_SIDE_MIDDLE);
|
||||
res->Normal = _box_normal[test.Axis][test.Side];
|
||||
if (res->ComputeContactPoint) {
|
||||
res->ContactPoint = line.Get_P0() + res->Fraction * line.Get_DP();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CollisionMath::Collide(const LineSegClass & line,const OBBoxClass & box,CastResultStruct * result)
|
||||
{
|
||||
// set up the test struct
|
||||
BoxTestStruct test;
|
||||
test.Min = box.Center - box.Extent;
|
||||
test.Max = box.Center + box.Extent;
|
||||
|
||||
test.P0 = (box.Basis.Transpose() * (line.Get_P0() - box.Center)) + box.Center;
|
||||
test.DP = box.Basis.Transpose() * line.Get_DP();
|
||||
|
||||
// check ray against the box, exit if the ray totally missed the box,
|
||||
if (!Test_Aligned_Box(&test)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if ray starts inside the box, don't collide
|
||||
if (test.Inside) {
|
||||
result->StartBad = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now, if this intersection is before any current intersection
|
||||
// that we've found, install our intersection
|
||||
if (test.Fraction < result->Fraction) {
|
||||
result->Fraction = test.Fraction;
|
||||
assert(test.Side != BOX_SIDE_MIDDLE);
|
||||
|
||||
switch (test.Axis) {
|
||||
case 0:
|
||||
result->Normal.Set(box.Basis[0][0],box.Basis[1][0],box.Basis[2][0]);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
result->Normal.Set(box.Basis[0][1],box.Basis[1][1],box.Basis[2][1]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
result->Normal.Set(box.Basis[0][2],box.Basis[1][2],box.Basis[2][2]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (test.Side == BOX_SIDE_NEGATIVE) {
|
||||
result->Normal = -result->Normal;
|
||||
}
|
||||
if (result->ComputeContactPoint) {
|
||||
result->ContactPoint = line.Get_P0() + result->Fraction * line.Get_DP();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Test_Aligned_Box -- used as the guts of the Box intersection tests *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/20/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline bool Test_Aligned_Box(BoxTestStruct * test)
|
||||
{
|
||||
int i;
|
||||
|
||||
// candidate intersection plane distance for each axis
|
||||
float candidateplane[3];
|
||||
|
||||
// t value along the ray for each axis
|
||||
float maxt[3];
|
||||
|
||||
// intersection point
|
||||
Vector3 coord;
|
||||
|
||||
// which "side" of the box for each axis
|
||||
int quadrant[3];
|
||||
bool inside = true;
|
||||
|
||||
for (i=0; i<3; i++) {
|
||||
if (test->P0[i] < test->Min[i]) {
|
||||
quadrant[i] = BOX_SIDE_NEGATIVE;
|
||||
candidateplane[i] = test->Min[i];
|
||||
inside = false;
|
||||
} else if (test->P0[i] > test->Max[i]) {
|
||||
quadrant[i] = BOX_SIDE_POSITIVE;
|
||||
candidateplane[i] = test->Max[i];
|
||||
inside = false;
|
||||
} else {
|
||||
quadrant[i] = BOX_SIDE_MIDDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Ray started out inside the box...
|
||||
*/
|
||||
if (inside) {
|
||||
test->Fraction = 0.0f;
|
||||
test->Inside = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
** Calculate the 3 distances to the candidate planes
|
||||
*/
|
||||
for (i=0; i<3; i++) {
|
||||
if (quadrant[i] != BOX_SIDE_MIDDLE && test->DP[i] != 0.0f) {
|
||||
maxt[i] = (candidateplane[i] - test->P0[i]) / test->DP[i];
|
||||
} else {
|
||||
maxt[i] = -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Get the largest of the maxt's for the final choice of intersection
|
||||
*/
|
||||
int intersection_plane = 0;
|
||||
|
||||
for (i=1; i<3; i++) {
|
||||
if (maxt[i] > maxt[intersection_plane]) {
|
||||
intersection_plane = i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If the ray is "in front" of all of the planes, return
|
||||
*/
|
||||
if (maxt[intersection_plane] < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check if the ray is inside the box, i.e. on the two planes which
|
||||
** are not the intersection planes, the intersection point should
|
||||
** be between the min and max of the box.
|
||||
*/
|
||||
for (i=0; i<3; i++) {
|
||||
|
||||
if (intersection_plane != i) {
|
||||
|
||||
coord[i] = test->P0[i] + maxt[intersection_plane] * test->DP[i];
|
||||
|
||||
if ((coord[i] < test->Min[i]) || (coord[i] > test->Max[i])) {
|
||||
|
||||
return false; // ray is outside the box
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
coord[i] = candidateplane[i];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Fill in the intersection values
|
||||
*/
|
||||
test->Fraction = maxt[intersection_plane];
|
||||
test->Inside = false;
|
||||
test->Axis = intersection_plane;
|
||||
test->Side = quadrant[intersection_plane];
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathline.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 3/16/00 3:46p $*
|
||||
* *
|
||||
* $Revision:: 1 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#ifndef COLMATHLINE_H
|
||||
#define COLMATHLINE_H
|
||||
|
||||
/*
|
||||
** Inline collision functions dealing with line segments
|
||||
*/
|
||||
|
||||
|
||||
inline CollisionMath::OverlapType CollisionMath::Overlap_Test
|
||||
(
|
||||
const Vector3 & min,
|
||||
const Vector3 & max,
|
||||
const LineSegClass & line
|
||||
)
|
||||
{
|
||||
AABoxClass box;
|
||||
box.Init_Min_Max(min,max);
|
||||
return CollisionMath::Overlap_Test(box,line);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1409
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp
Normal file
1409
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbobb.cpp
Normal file
File diff suppressed because it is too large
Load Diff
171
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbox.cpp
Normal file
171
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbox.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathobbox.cpp $*
|
||||
* *
|
||||
* Org Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* Author : Kenny Mitchell *
|
||||
* *
|
||||
* $Modtime:: 06/26/02 4:04p $*
|
||||
* *
|
||||
* $Revision:: 9 $*
|
||||
* *
|
||||
* 06/26/02 KM Matrix name change to avoid MAX conflicts *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "colmath.h"
|
||||
#include "aaplane.h"
|
||||
#include "plane.h"
|
||||
#include "lineseg.h"
|
||||
#include "tri.h"
|
||||
#include "sphere.h"
|
||||
#include "aabox.h"
|
||||
#include "obbox.h"
|
||||
#include "wwdebug.h"
|
||||
|
||||
|
||||
|
||||
// OBBox functions, where is operand B with respect to the OBBox
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const OBBoxClass & box,const Vector3 & point)
|
||||
{
|
||||
// transform point into box coordinate system
|
||||
Vector3 localpoint;
|
||||
Matrix3x3::Transpose_Rotate_Vector(box.Basis,(point - box.Center),&localpoint);
|
||||
|
||||
// if the point is outside any of the extents, it is outside the box
|
||||
if (WWMath::Fabs(localpoint.X) > box.Extent.X) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
if (WWMath::Fabs(localpoint.Y) > box.Extent.Y) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
if (WWMath::Fabs(localpoint.Z) > box.Extent.Z) {
|
||||
return OUTSIDE;
|
||||
}
|
||||
return INSIDE;
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const OBBoxClass & box,const LineSegClass & line)
|
||||
{
|
||||
CastResultStruct res;
|
||||
Collide(line,box,&res);
|
||||
return eval_overlap_collision(res);
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const OBBoxClass & box,const TriClass & tri)
|
||||
{
|
||||
CastResultStruct res;
|
||||
Collide(box,Vector3(0,0,0),tri,Vector3(0,0,0),&res);
|
||||
return eval_overlap_collision(res);
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const AABoxClass & aabox,const OBBoxClass & obbox)
|
||||
{
|
||||
if (CollisionMath::Intersection_Test(aabox,obbox)) {
|
||||
return BOTH; // inside or overlapping
|
||||
} else {
|
||||
return OUTSIDE;
|
||||
}
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const OBBoxClass & obbox,const AABoxClass & aabox)
|
||||
{
|
||||
if (CollisionMath::Intersection_Test(obbox,aabox)) {
|
||||
return BOTH; // inside or overlapping
|
||||
} else {
|
||||
return OUTSIDE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const OBBoxClass & box,const OBBoxClass & box2)
|
||||
{
|
||||
CastResultStruct res;
|
||||
Collide(box,Vector3(0,0,0),box2,Vector3(0,0,0),&res);
|
||||
return eval_overlap_collision(res);
|
||||
}
|
||||
|
||||
bool CollisionMath::Collide
|
||||
(
|
||||
const OBBoxClass & box,
|
||||
const Vector3 & move_vector,
|
||||
const PlaneClass & plane,
|
||||
CastResultStruct * result
|
||||
)
|
||||
{
|
||||
float frac;
|
||||
|
||||
float extent = box.Project_To_Axis(plane.N);
|
||||
float dist = Vector3::Dot_Product(plane.N,box.Center) + plane.D;
|
||||
float move = Vector3::Dot_Product(plane.N,move_vector);
|
||||
|
||||
if (dist > extent) {
|
||||
if (dist + move > extent) {
|
||||
// entire move ok!
|
||||
frac = 1.0f;
|
||||
} else {
|
||||
// partial move allowed
|
||||
frac = (extent - dist) / move;
|
||||
}
|
||||
|
||||
} else if (dist < -extent) {
|
||||
if (dist + move < -extent) {
|
||||
// entire move ok!
|
||||
frac = 1.0f;
|
||||
} else {
|
||||
// partial move allowed
|
||||
frac = (-extent - dist) / move;
|
||||
}
|
||||
} else {
|
||||
result->StartBad = true;
|
||||
result->Normal = plane.N;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (frac < result->Fraction) {
|
||||
result->Fraction = frac;
|
||||
result->Normal = plane.N;
|
||||
if (result->ComputeContactPoint) {
|
||||
|
||||
Vector3 move_dir(move_vector);
|
||||
move_dir.Normalize();
|
||||
float move_extent = Vector3::Dot_Product(move_dir,box.Extent);
|
||||
result->ContactPoint = box.Center + result->Fraction*move_vector + move_extent*move_dir;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
1510
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp
Normal file
1510
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathobbtri.cpp
Normal file
File diff suppressed because it is too large
Load Diff
197
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathplane.cpp
Normal file
197
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathplane.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathplane.cpp $*
|
||||
* *
|
||||
* Org Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* Author : Kenny Mitchell *
|
||||
* *
|
||||
* $Modtime:: 06/26/02 4:04p $*
|
||||
* *
|
||||
* $Revision:: 10 $*
|
||||
* *
|
||||
* 06/26/02 KM Matrix name change to avoid MAX conflicts *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "colmath.h"
|
||||
#include "colmathplane.h"
|
||||
#include "aaplane.h"
|
||||
#include "plane.h"
|
||||
#include "lineseg.h"
|
||||
#include "tri.h"
|
||||
#include "sphere.h"
|
||||
#include "aabox.h"
|
||||
#include "obbox.h"
|
||||
#include "wwdebug.h"
|
||||
|
||||
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const AAPlaneClass & plane,const Vector3 & point)
|
||||
{
|
||||
float delta = point[plane.Normal] - plane.Dist;
|
||||
if (delta > COINCIDENCE_EPSILON) {
|
||||
return POS;
|
||||
}
|
||||
if (delta < -COINCIDENCE_EPSILON) {
|
||||
return NEG;
|
||||
}
|
||||
return ON;
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const AAPlaneClass & plane,const LineSegClass & line)
|
||||
{
|
||||
int mask = 0;
|
||||
mask |= CollisionMath::Overlap_Test(plane,line.Get_P0());
|
||||
mask |= CollisionMath::Overlap_Test(plane,line.Get_P1());
|
||||
return eval_overlap_mask(mask);
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const AAPlaneClass & plane,const TriClass & tri)
|
||||
{
|
||||
int mask = 0;
|
||||
mask |= CollisionMath::Overlap_Test(plane,*tri.V[0]);
|
||||
mask |= CollisionMath::Overlap_Test(plane,*tri.V[1]);
|
||||
mask |= CollisionMath::Overlap_Test(plane,*tri.V[2]);
|
||||
return eval_overlap_mask(mask);
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const AAPlaneClass & plane,const SphereClass & sphere)
|
||||
{
|
||||
float delta = sphere.Center[plane.Normal] - plane.Dist;
|
||||
if (delta > sphere.Radius) {
|
||||
return POS;
|
||||
}
|
||||
if (delta < sphere.Radius) {
|
||||
return NEG;
|
||||
}
|
||||
return BOTH;
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const AAPlaneClass & plane,const AABoxClass & box)
|
||||
{
|
||||
float delta;
|
||||
int mask = 0;
|
||||
|
||||
// check the 'min' side of the box
|
||||
delta = (box.Center[plane.Normal] - box.Extent[plane.Normal]) - plane.Dist;
|
||||
if (delta > WWMATH_EPSILON) {
|
||||
mask |= POS;
|
||||
} else if (delta < -WWMATH_EPSILON) {
|
||||
mask |= NEG;
|
||||
} else {
|
||||
mask |= ON;
|
||||
}
|
||||
|
||||
// check the 'max' side of the box
|
||||
delta = (box.Center[plane.Normal] + box.Extent[plane.Normal]) - plane.Dist;
|
||||
if (delta > WWMATH_EPSILON) {
|
||||
mask |= POS;
|
||||
} else if (delta < -WWMATH_EPSILON) {
|
||||
mask |= NEG;
|
||||
} else {
|
||||
mask |= ON;
|
||||
}
|
||||
|
||||
return eval_overlap_mask(mask);
|
||||
}
|
||||
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const AAPlaneClass & /*plane*/,const OBBoxClass & /*box*/)
|
||||
{
|
||||
// TODO
|
||||
WWASSERT(0);
|
||||
return POS;
|
||||
}
|
||||
|
||||
|
||||
// Plane functions. Where is operand B with respect to the plane
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const PlaneClass & plane,const LineSegClass & line)
|
||||
{
|
||||
int mask = 0;
|
||||
mask |= CollisionMath::Overlap_Test(plane,line.Get_P0());
|
||||
mask |= CollisionMath::Overlap_Test(plane,line.Get_P1());
|
||||
return eval_overlap_mask(mask);
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const PlaneClass & plane,const TriClass & tri)
|
||||
{
|
||||
int mask = 0;
|
||||
mask |= CollisionMath::Overlap_Test(plane,*tri.V[0]);
|
||||
mask |= CollisionMath::Overlap_Test(plane,*tri.V[1]);
|
||||
mask |= CollisionMath::Overlap_Test(plane,*tri.V[2]);
|
||||
return eval_overlap_mask(mask);
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const PlaneClass & plane,const SphereClass & sphere)
|
||||
{
|
||||
float dist = Vector3::Dot_Product(sphere.Center,plane.N) - plane.D;
|
||||
if (dist > sphere.Radius) {
|
||||
return POS;
|
||||
}
|
||||
if (dist < -sphere.Radius) {
|
||||
return NEG;
|
||||
}
|
||||
return BOTH;
|
||||
}
|
||||
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const PlaneClass & plane,const OBBoxClass & box)
|
||||
{
|
||||
// rotate the plane normal into box coordinates
|
||||
Vector3 local_normal;
|
||||
Vector3 posfarpt;
|
||||
Vector3 negfarpt;
|
||||
Matrix3x3::Transpose_Rotate_Vector(box.Basis,plane.N,&local_normal);
|
||||
|
||||
get_far_extent(local_normal,box.Extent,&posfarpt);
|
||||
|
||||
// transform the two extreme box coordinates into world space
|
||||
Matrix3x3::Rotate_Vector(box.Basis,posfarpt,&posfarpt);
|
||||
negfarpt = -posfarpt;
|
||||
posfarpt += box.Center;
|
||||
negfarpt += box.Center;
|
||||
|
||||
// overlap test
|
||||
if (Overlap_Test(plane,negfarpt) == POS) {
|
||||
return POS;
|
||||
}
|
||||
if (Overlap_Test(plane,posfarpt) == NEG) {
|
||||
return NEG;
|
||||
}
|
||||
return BOTH;
|
||||
}
|
||||
154
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathplane.h
Normal file
154
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/colmathplane.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathplane.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 3/29/00 4:42p $*
|
||||
* *
|
||||
* $Revision:: 2 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* get_far_extent -- gets extents of a box projected onto an axis *
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between a plane and a point *
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between a plane and an AABox *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#ifndef COLMATHPLANE_H
|
||||
#define COLMATHPLANE_H
|
||||
|
||||
#include "always.h"
|
||||
#include "plane.h"
|
||||
#include "aabox.h"
|
||||
|
||||
/*
|
||||
** Inline collision functions dealing with planes
|
||||
** This module is meant to be included only in .CPP files after you include colmath.h
|
||||
** It is not automatically included in order to reduce file dependencies...
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
* get_far_extent -- gets extents of a box projected onto an axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/29/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void get_far_extent(const Vector3 & normal,const Vector3 & extent,Vector3 * posfarpt)
|
||||
{
|
||||
if (WWMath::Fast_Is_Float_Positive(normal.X)) {
|
||||
posfarpt->X = extent.X;
|
||||
} else {
|
||||
posfarpt->X = -extent.X;
|
||||
}
|
||||
|
||||
if (WWMath::Fast_Is_Float_Positive(normal.Y)) {
|
||||
posfarpt->Y = extent.Y;
|
||||
} else {
|
||||
posfarpt->Y = -extent.Y;
|
||||
}
|
||||
|
||||
if (WWMath::Fast_Is_Float_Positive(normal.Z)) {
|
||||
posfarpt->Z = extent.Z;
|
||||
} else {
|
||||
posfarpt->Z = -extent.Z;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between a plane and a point *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/29/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
inline
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const PlaneClass & plane,const Vector3 & point)
|
||||
{
|
||||
float delta = Vector3::Dot_Product(point,plane.N) - plane.D;
|
||||
if (delta > COINCIDENCE_EPSILON) {
|
||||
return POS;
|
||||
}
|
||||
if (delta < -COINCIDENCE_EPSILON) {
|
||||
return NEG;
|
||||
}
|
||||
return ON;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Tests overlap between a plane and an AABox *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/29/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
inline
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const PlaneClass & plane,const AABoxClass & box)
|
||||
{
|
||||
// First, we determine the the near and far points of the box in the
|
||||
// direction of the plane normal
|
||||
Vector3 posfarpt;
|
||||
Vector3 negfarpt;
|
||||
|
||||
get_far_extent(plane.N,box.Extent,&posfarpt);
|
||||
|
||||
negfarpt = -posfarpt;
|
||||
posfarpt += box.Center;
|
||||
negfarpt += box.Center;
|
||||
if (Overlap_Test(plane,negfarpt) == POS) {
|
||||
return POS;
|
||||
}
|
||||
if (Overlap_Test(plane,posfarpt) == NEG) {
|
||||
return NEG;
|
||||
}
|
||||
return BOTH;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/colmathsphere.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 4/25/01 2:05p $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* CollisionMath::Intersection_Test -- Sphere - AAbox intersection *
|
||||
* CollisionMath::Intersection_Test -- Sphere - OBBox intersection *
|
||||
* CollisionMath::Overlap_Test -- Sphere - Point overlap test *
|
||||
* CollisionMath::Overlap_Test -- sphere line overlap test *
|
||||
* CollisionMath::Overlap_Test -- sphere triangle overlap test *
|
||||
* CollisionMath::Overlap_Test -- Sphere - Sphere overlap test *
|
||||
* CollisionMath::Overlap_Test -- Sphere - AABox overlap test *
|
||||
* CollisionMath::Overlap_Test -- Sphere - OBBox overlap test *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "colmath.h"
|
||||
#include "aaplane.h"
|
||||
#include "plane.h"
|
||||
#include "lineseg.h"
|
||||
#include "tri.h"
|
||||
#include "sphere.h"
|
||||
#include "aabox.h"
|
||||
#include "obbox.h"
|
||||
#include "wwdebug.h"
|
||||
|
||||
|
||||
// Sphere Intersection fucntions. Does the sphere intersect the passed in object
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Intersection_Test -- Sphere - AAbox intersection *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CollisionMath::Intersection_Test(const SphereClass & sphere,const AABoxClass & box)
|
||||
{
|
||||
/*
|
||||
** Simple but slightly inaccurate test, expand the box by the sphere's radius, then
|
||||
** test whether the sphere is contained in that new box. This is actually testing
|
||||
** against a cube which encloses the sphere...
|
||||
*/
|
||||
Vector3 dc = box.Center - sphere.Center;
|
||||
if (WWMath::Fabs(dc.X) < box.Extent.X + sphere.Radius) return false;
|
||||
if (WWMath::Fabs(dc.Y) < box.Extent.Y + sphere.Radius) return false;
|
||||
if (WWMath::Fabs(dc.Z) < box.Extent.Z + sphere.Radius) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Intersection_Test -- Sphere - OBBox intersection *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
bool CollisionMath::Intersection_Test(const SphereClass & sphere,const OBBoxClass & box)
|
||||
{
|
||||
/*
|
||||
** Compute the sphere's position in the box's coordinate system
|
||||
*/
|
||||
Matrix3D tm(box.Basis,box.Center);
|
||||
Vector3 box_rel_center;
|
||||
Matrix3D::Inverse_Transform_Vector(tm,sphere.Center,&box_rel_center);
|
||||
|
||||
if (box.Extent.X < WWMath::Fabs(box_rel_center.X)) return false;
|
||||
if (box.Extent.Y < WWMath::Fabs(box_rel_center.Y)) return false;
|
||||
if (box.Extent.Z < WWMath::Fabs(box_rel_center.Z)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sphere Overlap functions. Where is operand B with respect to the sphere
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Sphere - Point overlap test *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const SphereClass & sphere,const Vector3 & point)
|
||||
{
|
||||
float r2 = (point - sphere.Center).Length2();
|
||||
if (r2 < sphere.Radius * sphere.Radius - COINCIDENCE_EPSILON) {
|
||||
return NEG;
|
||||
}
|
||||
if (r2 > sphere.Radius * sphere.Radius + COINCIDENCE_EPSILON) {
|
||||
return POS;
|
||||
}
|
||||
return ON;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- sphere line overlap test *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const SphereClass & /*sphere*/,const LineSegClass & /*line*/)
|
||||
{
|
||||
WWASSERT(0); //TODO
|
||||
return POS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- sphere triangle overlap test *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const SphereClass & /*sphere*/,const TriClass & /*tri*/)
|
||||
{
|
||||
WWASSERT(0); //TODO
|
||||
return POS;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Sphere - Sphere overlap test *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const SphereClass & sphere,const SphereClass & sphere2)
|
||||
{
|
||||
CollisionMath::OverlapType retval = OUTSIDE;
|
||||
|
||||
float radius = sphere.Radius + sphere2.Radius;
|
||||
float dist2 = (sphere2.Center - sphere.Center).Length2();
|
||||
|
||||
if (dist2 == 0 && sphere.Radius == sphere2.Radius) {
|
||||
retval = OVERLAPPED;
|
||||
} else if (dist2 <= radius * radius - COINCIDENCE_EPSILON) {
|
||||
retval = INSIDE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Sphere - AABox overlap test *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const SphereClass & sphere,const AABoxClass & aabox)
|
||||
{
|
||||
// TODO: overlap function that detects containment?
|
||||
return ( Intersection_Test(sphere,aabox) ? BOTH : POS );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* CollisionMath::Overlap_Test -- Sphere - OBBox overlap test *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/25/2001 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
CollisionMath::OverlapType
|
||||
CollisionMath::Overlap_Test(const SphereClass & sphere,const OBBoxClass & obbox)
|
||||
{
|
||||
// TODO: overlap function that detects containment?
|
||||
return ( Intersection_Test(sphere,obbox) ? BOTH : POS );
|
||||
}
|
||||
|
||||
|
||||
154
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/cullsys.cpp
Normal file
154
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/cullsys.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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:: /VSS_Sync/wwmath/cullsys.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 10/16/00 11:42a $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "cullsys.h"
|
||||
#include "wwdebug.h"
|
||||
#include "wwprofile.h"
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
**
|
||||
** CullableClass Implementation
|
||||
**
|
||||
*************************************************************************/
|
||||
CullableClass::CullableClass(void) :
|
||||
CullLink(NULL),
|
||||
NextCollected(NULL)
|
||||
{
|
||||
CullBox.Init(Vector3(0,0,0),Vector3(1,1,1));
|
||||
}
|
||||
|
||||
CullableClass::~CullableClass(void)
|
||||
{
|
||||
// the cull system that contains us is responsible for any culling link
|
||||
// so we better be out of it and it should have cleared our pointer before
|
||||
// we are deleted.
|
||||
WWASSERT(CullLink == NULL);
|
||||
}
|
||||
|
||||
void CullableClass::Set_Cull_Box(const AABoxClass & box,bool just_loaded)
|
||||
{
|
||||
CullBox = box;
|
||||
|
||||
WWPROFILE("Cullable::Set_Cull_Box");
|
||||
|
||||
// Just_loaded flag allows us to update the box without notifying the
|
||||
// culling system. Use this when you've saved and loaded the linkage
|
||||
// so you know you're in the right node of the culling system...
|
||||
if (!just_loaded) {
|
||||
CullSystemClass * sys = Get_Culling_System();
|
||||
if (sys != NULL) {
|
||||
sys->Update_Culling(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CullableClass::Set_Culling_System(CullSystemClass * sys)
|
||||
{
|
||||
if (CullLink) {
|
||||
CullLink->Set_Culling_System(sys);
|
||||
}
|
||||
}
|
||||
|
||||
CullSystemClass * CullableClass::Get_Culling_System(void) const
|
||||
{
|
||||
if (CullLink) {
|
||||
return CullLink->Get_Culling_System();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
**
|
||||
** CullSystemClass Implementation
|
||||
**
|
||||
** The base CullSystemClass mainly contains code for maintaining the
|
||||
** current collection list and iterating through it.
|
||||
**
|
||||
*************************************************************************/
|
||||
CullSystemClass::CullSystemClass(void) :
|
||||
CollectionHead(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CullSystemClass::~CullSystemClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
// NOTE: THE Get_() functions currently are the same as the Peek_() functions (e.g., they do not
|
||||
// add a Ref). This is wrong and will be fixed.
|
||||
CullableClass * CullSystemClass::Get_First_Collected_Object_Internal(void)
|
||||
{
|
||||
return CollectionHead;
|
||||
}
|
||||
|
||||
CullableClass * CullSystemClass::Get_Next_Collected_Object_Internal(CullableClass * obj)
|
||||
{
|
||||
if (obj != NULL) {
|
||||
return obj->NextCollected;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CullableClass * CullSystemClass::Peek_First_Collected_Object_Internal(void)
|
||||
{
|
||||
return CollectionHead;
|
||||
}
|
||||
|
||||
CullableClass * CullSystemClass::Peek_Next_Collected_Object_Internal(CullableClass * obj)
|
||||
{
|
||||
if (obj != NULL) {
|
||||
return obj->NextCollected;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CullSystemClass::Reset_Collection(void)
|
||||
{
|
||||
CollectionHead = NULL;
|
||||
}
|
||||
|
||||
void CullSystemClass::Add_To_Collection(CullableClass * obj)
|
||||
{
|
||||
WWASSERT(obj != NULL);
|
||||
obj->NextCollected = CollectionHead;
|
||||
CollectionHead = obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
201
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/cullsys.h
Normal file
201
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/cullsys.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/cullsys.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 5/08/01 6:33p $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef CULLSYS_H
|
||||
#define CULLSYS_H
|
||||
|
||||
#include "wwdebug.h"
|
||||
#include "stdlib.h"
|
||||
#include "refcount.h"
|
||||
#include "aabox.h"
|
||||
|
||||
class CullableClass;
|
||||
class CullSystemClass;
|
||||
class FrustumClass;
|
||||
|
||||
/*
|
||||
** CullLinkClass
|
||||
** This class will serve as a base class for the various types of linkage information
|
||||
** that the Cullable instances will need. Each CullableClass will have a pointer to
|
||||
** a class derived from CullLinkClass where the different culling systems can store
|
||||
** things.
|
||||
*/
|
||||
class CullLinkClass
|
||||
{
|
||||
public:
|
||||
WWINLINE CullLinkClass(CullSystemClass * system) { System = system; WWASSERT(System); }
|
||||
virtual ~CullLinkClass(void) { WWASSERT(System == NULL); }
|
||||
|
||||
WWINLINE void Set_Culling_System(CullSystemClass * sys) { System = sys; }
|
||||
WWINLINE CullSystemClass * Get_Culling_System(void) { return System; }
|
||||
|
||||
protected:
|
||||
CullSystemClass * System;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** CullableClass
|
||||
** This is the base class for any object that can be inserted into a culling system
|
||||
** This class provides an axis aligned bounding box and some linkage variables which
|
||||
** allow it to be processed by any culling system.
|
||||
*/
|
||||
class CullableClass : public RefCountClass
|
||||
{
|
||||
public:
|
||||
|
||||
CullableClass(void);
|
||||
virtual ~CullableClass(void);
|
||||
|
||||
/*
|
||||
** Access to the culling box for this object. When you set the cull box, you are
|
||||
** basically guaranteeing that the object is contained within the given box. The
|
||||
** object will automatically be updated in whatever culling system it is currently
|
||||
** contained in (if any)
|
||||
*/
|
||||
WWINLINE const AABoxClass & Get_Cull_Box(void) const { return CullBox; }
|
||||
void Set_Cull_Box(const AABoxClass & box,bool just_loaded = false);
|
||||
|
||||
/*
|
||||
** These functions are used by various culling systems to manage the linkage
|
||||
** pointers. *The average user should NEVER call these*
|
||||
*/
|
||||
void Set_Culling_System(CullSystemClass * sys);
|
||||
CullSystemClass * Get_Culling_System(void) const;
|
||||
WWINLINE void Set_Cull_Link(CullLinkClass * c) { CullLink = c; }
|
||||
WWINLINE CullLinkClass * Get_Cull_Link(void) const { return CullLink; }
|
||||
|
||||
private:
|
||||
|
||||
WWINLINE void Set_Next_Collected(CullableClass * c) { NextCollected = c; }
|
||||
WWINLINE CullableClass * Get_Next_Collected(void) { return NextCollected; }
|
||||
|
||||
/*
|
||||
** Culling Data
|
||||
** Each object can be linked into various types of culling systems.
|
||||
** Each culling system can use its own linkage data structure (derived
|
||||
** from CullLinkClass) to keep track of the object. The CullData pointer
|
||||
** will point to one of the culling link objects and NULL
|
||||
** if its not in any system.
|
||||
*/
|
||||
CullLinkClass * CullLink;
|
||||
|
||||
/*
|
||||
** Bounding Box
|
||||
** Any objects derived from Cullable should update the bounding box
|
||||
** whenever the object moves or changes size. In order to do this,
|
||||
** call Set_Cull_Box...
|
||||
*/
|
||||
AABoxClass CullBox;
|
||||
|
||||
/*
|
||||
** NextCollected
|
||||
** This pointer is used by the culling system to keep a singly linked
|
||||
** list of cullable object that have been "collected".
|
||||
*/
|
||||
CullableClass * NextCollected;
|
||||
|
||||
// Not Implemented:
|
||||
CullableClass(const CullableClass & src);
|
||||
CullableClass & operator = (const CullableClass & src);
|
||||
|
||||
friend class CullSystemClass;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** CullSystemClass
|
||||
** Base class of any culling system. This interface exists so that things can
|
||||
** be shuffled around without having explicit knowledge of what system they are in.
|
||||
*/
|
||||
class CullSystemClass
|
||||
{
|
||||
public:
|
||||
|
||||
CullSystemClass(void);
|
||||
virtual ~CullSystemClass(void);
|
||||
|
||||
/*
|
||||
** Collect_Objects. Updates the internal collection list with the
|
||||
** objects that overlap the given primitive.
|
||||
** WARNING: This builds an internal list that is only valid until
|
||||
** another list is built, only one list can be valid at any time.
|
||||
** WARNING: Always call Reset_Collection if you want to start a
|
||||
** fresh collection!
|
||||
*/
|
||||
void Reset_Collection(void);
|
||||
virtual void Collect_Objects(const Vector3 & point) = 0;
|
||||
virtual void Collect_Objects(const AABoxClass & box) = 0;
|
||||
virtual void Collect_Objects(const OBBoxClass & box) = 0;
|
||||
virtual void Collect_Objects(const FrustumClass & frustum) = 0;
|
||||
|
||||
/*
|
||||
** This object has moved or changed size, update it
|
||||
*/
|
||||
virtual void Update_Culling(CullableClass * obj) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
** Iterate through the collected objects
|
||||
*/
|
||||
CullableClass * Get_First_Collected_Object_Internal(void);
|
||||
CullableClass * Get_Next_Collected_Object_Internal(CullableClass * obj);
|
||||
CullableClass * Peek_First_Collected_Object_Internal(void);
|
||||
CullableClass * Peek_Next_Collected_Object_Internal(CullableClass * obj);
|
||||
|
||||
/*
|
||||
** Build the list of collected objects
|
||||
*/
|
||||
void Add_To_Collection(CullableClass * obj);
|
||||
|
||||
/*
|
||||
** Pointer to the head of the current collection of objects
|
||||
*/
|
||||
CullableClass * CollectionHead;
|
||||
|
||||
friend class CullableClass;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
62
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/culltype.h
Normal file
62
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/culltype.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/culltype.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 10/23/98 2:34p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef CULLTYPE_H
|
||||
#define CULLTYPE_H
|
||||
|
||||
#include "always.h"
|
||||
|
||||
/*
|
||||
** CullType is an enumeration of the possible results of a culling
|
||||
** operation. It is placed here so that all of the different cull functions
|
||||
** (which are scattered throughout WWMath, WW3D, WWPhys, etc) can
|
||||
** communicate the result in a consistent way
|
||||
*/
|
||||
|
||||
typedef enum CULLTYPE
|
||||
{
|
||||
CULL_OUTSIDE = 0, // the object was completely outside the culling volume
|
||||
CULL_INTERSECTING, // the object intersects an edge of the culling volume
|
||||
CULL_INSIDE // the object is completely inside the culling volume
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
591
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/curve.cpp
Normal file
591
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/curve.cpp
Normal file
@@ -0,0 +1,591 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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:: /VSS_Sync/wwmath/curve.cpp $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Vss_sync $*
|
||||
* *
|
||||
* $Modtime:: 6/13/01 2:18p $*
|
||||
* *
|
||||
* $Revision:: 9 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "curve.h"
|
||||
#include "wwdebug.h"
|
||||
#include "persistfactory.h"
|
||||
#include "wwmathids.h"
|
||||
#include "wwhack.h"
|
||||
|
||||
/*
|
||||
** Force-Link this module because the linker can't detect that we actually need it...
|
||||
*/
|
||||
DECLARE_FORCE_LINK(curve);
|
||||
|
||||
/*
|
||||
** Persist factories and chunk-id's used to save and load.
|
||||
*/
|
||||
SimplePersistFactoryClass<LinearCurve3DClass,WWMATH_CHUNKID_LINEARCURVE3D> _LinearCurve3DFactory;
|
||||
SimplePersistFactoryClass<LinearCurve1DClass,WWMATH_CHUNKID_LINEARCURVE1D> _LinearCurve1DFactory;
|
||||
|
||||
enum
|
||||
{
|
||||
// ID's used by Curve3D
|
||||
CURVE3D_CHUNK_VARIABLES = 0x00020651,
|
||||
CURVE3D_CHUNK_KEYS,
|
||||
|
||||
CURVE3D_VARIABLE_ISLOOPING = 0x00,
|
||||
CURVE3D_VARIABLE_KEYCOUNT,
|
||||
|
||||
// ID's used by LinearCurve3D
|
||||
LINEARCURVE3D_CHUNK_CURVE3D = 0x00020653,
|
||||
|
||||
// ID's used by Curve1D
|
||||
CURVE1D_CHUNK_VARIABLES = 0x00020655,
|
||||
CURVE1D_CHUNK_KEYS,
|
||||
|
||||
CURVE1D_VARIABLE_ISLOOPING = 0x00,
|
||||
CURVE1D_VARIABLE_KEYCOUNT,
|
||||
|
||||
// ID's used by LinearCurve1D
|
||||
LINEARCURVE1D_CHUNK_CURVE1D = 0x00020657,
|
||||
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
**
|
||||
** Curve3DCLass Implementation
|
||||
**
|
||||
***********************************************************************************************/
|
||||
Curve3DClass::Curve3DClass(void) :
|
||||
IsLooping(false)
|
||||
{
|
||||
}
|
||||
|
||||
Curve3DClass::Curve3DClass(const Curve3DClass & that)
|
||||
{
|
||||
*this = that;
|
||||
}
|
||||
|
||||
Curve3DClass::~Curve3DClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
Curve3DClass & Curve3DClass::operator = (const Curve3DClass & that)
|
||||
{
|
||||
IsLooping = that.IsLooping;
|
||||
Keys = that.Keys;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Curve3DClass::Is_Looping(void)
|
||||
{
|
||||
return IsLooping;
|
||||
}
|
||||
|
||||
void Curve3DClass::Set_Looping(bool onoff)
|
||||
{
|
||||
IsLooping = onoff;
|
||||
}
|
||||
|
||||
float Curve3DClass::Get_Start_Time(void)
|
||||
{
|
||||
if (Keys.Count() > 0) {
|
||||
return Keys[0].Time;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
float Curve3DClass::Get_End_Time(void)
|
||||
{
|
||||
if (Keys.Count() > 0) {
|
||||
return Keys[Keys.Count() - 1].Time;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
int Curve3DClass::Key_Count(void)
|
||||
{
|
||||
return Keys.Count();
|
||||
}
|
||||
|
||||
void Curve3DClass::Get_Key(int i,Vector3 * set_point,float * set_t)
|
||||
{
|
||||
assert(i >= 0);
|
||||
assert(i < Keys.Count());
|
||||
if (set_point != NULL) {
|
||||
*set_point = Keys[i].Point;
|
||||
}
|
||||
if (set_t != NULL) {
|
||||
*set_t = Keys[i].Time;
|
||||
}
|
||||
}
|
||||
|
||||
void Curve3DClass::Set_Key(int i,const Vector3 & point)
|
||||
{
|
||||
assert(i >= 0);
|
||||
assert(i < Keys.Count());
|
||||
Keys[i].Point = point;
|
||||
}
|
||||
|
||||
|
||||
int Curve3DClass::Add_Key(const Vector3 & point,float t)
|
||||
{
|
||||
int idx = 0;
|
||||
while (idx < Keys.Count() && Keys[idx].Time < t) {
|
||||
idx++;
|
||||
}
|
||||
|
||||
KeyClass newkey;
|
||||
newkey.Point = point;
|
||||
newkey.Time = t;
|
||||
|
||||
Keys.Insert(idx,newkey);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void Curve3DClass::Remove_Key(int i)
|
||||
{
|
||||
assert(i >= 0);
|
||||
assert(i < Keys.Count());
|
||||
Keys.Delete(i);
|
||||
}
|
||||
|
||||
void Curve3DClass::Clear_Keys(void)
|
||||
{
|
||||
Keys.Clear();
|
||||
}
|
||||
|
||||
void Curve3DClass::Find_Interval(float time,int * i0,int * i1,float * t)
|
||||
{
|
||||
WWASSERT(time >= Keys[0].Time);
|
||||
WWASSERT(time <= Keys[Keys.Count()-1].Time);
|
||||
|
||||
int i=0;
|
||||
while (time > Keys[i+1].Time) {
|
||||
i++;
|
||||
}
|
||||
*i0 = i;
|
||||
*i1 = i+1;
|
||||
*t = (time - Keys[i].Time) / (Keys[i+1].Time - Keys[i].Time);
|
||||
}
|
||||
|
||||
bool Curve3DClass::Save(ChunkSaveClass & csave)
|
||||
{
|
||||
int keycount = Keys.Count();
|
||||
csave.Begin_Chunk(CURVE3D_CHUNK_VARIABLES);
|
||||
WRITE_MICRO_CHUNK(csave,CURVE3D_VARIABLE_ISLOOPING,IsLooping);
|
||||
WRITE_MICRO_CHUNK(csave,CURVE3D_VARIABLE_KEYCOUNT,keycount);
|
||||
csave.End_Chunk();
|
||||
|
||||
// Saving the keys, Note that if the format of a key changes we'll
|
||||
// need a new chunk. (I didn't wrap each variable in its own chunk)
|
||||
csave.Begin_Chunk(CURVE3D_CHUNK_KEYS);
|
||||
for (int i=0; i<keycount; i++) {
|
||||
csave.Write(&(Keys[i].Point),sizeof(Keys[i].Point));
|
||||
csave.Write(&(Keys[i].Time),sizeof(Keys[i].Time));
|
||||
}
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Curve3DClass::Load(ChunkLoadClass & cload)
|
||||
{
|
||||
int i;
|
||||
int keycount = 0;
|
||||
KeyClass newkey;
|
||||
|
||||
// reset the curve
|
||||
Keys.Delete_All();
|
||||
|
||||
// read in the chunks
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case CURVE3D_CHUNK_VARIABLES:
|
||||
|
||||
while (cload.Open_Micro_Chunk()) {
|
||||
switch(cload.Cur_Micro_Chunk_ID()) {
|
||||
READ_MICRO_CHUNK(cload,CURVE3D_VARIABLE_ISLOOPING,IsLooping);
|
||||
READ_MICRO_CHUNK(cload,CURVE3D_VARIABLE_KEYCOUNT,keycount);
|
||||
}
|
||||
cload.Close_Micro_Chunk();
|
||||
}
|
||||
break;
|
||||
|
||||
case CURVE3D_CHUNK_KEYS:
|
||||
for (i=0; i<keycount; i++) {
|
||||
cload.Read(&(newkey.Point),sizeof(newkey.Point));
|
||||
cload.Read(&(newkey.Time),sizeof(newkey.Time));
|
||||
Keys.Add(newkey);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
**
|
||||
** LinearCurve3DClass Implementation
|
||||
** Linear curve, linearly interpolates the keys
|
||||
**
|
||||
***********************************************************************************************/
|
||||
void LinearCurve3DClass::Evaluate(float time,Vector3 * set_val)
|
||||
{
|
||||
if (time < Keys[0].Time) {
|
||||
*set_val = Keys[0].Point;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time >= Keys[Keys.Count() - 1].Time) {
|
||||
*set_val = Keys[Keys.Count() - 1].Point;
|
||||
return;
|
||||
}
|
||||
|
||||
int i0,i1;
|
||||
float t;
|
||||
Find_Interval(time,&i0,&i1,&t);
|
||||
|
||||
*set_val = Keys[i0].Point + t * (Keys[i1].Point - Keys[i0].Point);
|
||||
}
|
||||
|
||||
const PersistFactoryClass & LinearCurve3DClass::Get_Factory(void) const
|
||||
{
|
||||
return _LinearCurve3DFactory;
|
||||
}
|
||||
|
||||
bool LinearCurve3DClass::Save(ChunkSaveClass & csave)
|
||||
{
|
||||
csave.Begin_Chunk(LINEARCURVE3D_CHUNK_CURVE3D);
|
||||
Curve3DClass::Save(csave);
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinearCurve3DClass::Load(ChunkLoadClass & cload)
|
||||
{
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case LINEARCURVE3D_CHUNK_CURVE3D:
|
||||
Curve3DClass::Load(cload);
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
**
|
||||
** Curve1DClass
|
||||
**
|
||||
***********************************************************************************************/
|
||||
Curve1DClass::Curve1DClass(void) :
|
||||
IsLooping(false)
|
||||
{
|
||||
}
|
||||
|
||||
Curve1DClass::Curve1DClass(const Curve1DClass & that)
|
||||
{
|
||||
*this = that;
|
||||
}
|
||||
|
||||
Curve1DClass::~Curve1DClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
Curve1DClass & Curve1DClass::operator = (const Curve1DClass & that)
|
||||
{
|
||||
IsLooping = that.IsLooping;
|
||||
Keys = that.Keys;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Curve1DClass::Is_Looping(void)
|
||||
{
|
||||
return IsLooping;
|
||||
}
|
||||
|
||||
void Curve1DClass::Set_Looping(bool onoff)
|
||||
{
|
||||
IsLooping = onoff;
|
||||
}
|
||||
|
||||
float Curve1DClass::Get_Start_Time(void)
|
||||
{
|
||||
if (Keys.Count() > 0) {
|
||||
return Keys[0].Time;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
float Curve1DClass::Get_End_Time(void)
|
||||
{
|
||||
if (Keys.Count() > 0) {
|
||||
return Keys[Keys.Count() - 1].Time;
|
||||
} else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
int Curve1DClass::Key_Count(void)
|
||||
{
|
||||
return Keys.Count();
|
||||
}
|
||||
|
||||
void Curve1DClass::Get_Key(int i,float * set_point,float * set_t,unsigned int * extra)
|
||||
{
|
||||
assert(i >= 0);
|
||||
assert(i < Keys.Count());
|
||||
if (set_point != NULL) {
|
||||
*set_point = Keys[i].Point;
|
||||
}
|
||||
if (set_t != NULL) {
|
||||
*set_t = Keys[i].Time;
|
||||
}
|
||||
if (extra != NULL) {
|
||||
*extra = Keys[i].Extra;
|
||||
}
|
||||
}
|
||||
|
||||
void Curve1DClass::Set_Key(int i,float point,unsigned int extra)
|
||||
{
|
||||
assert(i >= 0);
|
||||
assert(i < Keys.Count());
|
||||
Keys[i].Point = point;
|
||||
Keys[i].Extra = extra;
|
||||
}
|
||||
|
||||
|
||||
int Curve1DClass::Add_Key(float point,float t,unsigned int extra)
|
||||
{
|
||||
int idx = 0;
|
||||
while (idx < Keys.Count() && Keys[idx].Time < t) {
|
||||
idx++;
|
||||
}
|
||||
|
||||
KeyClass newkey;
|
||||
newkey.Point = point;
|
||||
newkey.Time = t;
|
||||
newkey.Extra = extra;
|
||||
|
||||
Keys.Insert(idx,newkey);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void Curve1DClass::Remove_Key(int i)
|
||||
{
|
||||
assert(i >= 0);
|
||||
assert(i < Keys.Count());
|
||||
Keys.Delete(i);
|
||||
}
|
||||
|
||||
void Curve1DClass::Clear_Keys(void)
|
||||
{
|
||||
Keys.Clear();
|
||||
}
|
||||
|
||||
void Curve1DClass::Find_Interval(float time,int * i0,int * i1,float * t)
|
||||
{
|
||||
if (IsLooping) {
|
||||
if (time < Keys[0].Time) {
|
||||
*i0 = Keys.Count() - 1;
|
||||
*i1 = 0;
|
||||
float interval = 1.0f - Keys[*i0].Time + Keys[*i1].Time;
|
||||
*t = (1.0f - Keys[*i0].Time + time) / interval;
|
||||
return;
|
||||
}
|
||||
else if (time > Keys[Keys.Count() - 1].Time) {
|
||||
*i0 = Keys.Count() - 1;
|
||||
*i1 = 0;
|
||||
float interval = 1.0f - Keys[*i0].Time + Keys[*i1].Time;
|
||||
*t = (time - Keys[*i0].Time) / interval;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
WWASSERT(time >= Keys[0].Time);
|
||||
WWASSERT(time <= Keys[Keys.Count()-1].Time);
|
||||
}
|
||||
|
||||
int i=0;
|
||||
while (time > Keys[i+1].Time) {
|
||||
i++;
|
||||
}
|
||||
*i0 = i;
|
||||
*i1 = i+1;
|
||||
*t = (time - Keys[i].Time) / (Keys[i+1].Time - Keys[i].Time);
|
||||
}
|
||||
|
||||
bool Curve1DClass::Save(ChunkSaveClass & csave)
|
||||
{
|
||||
int keycount = Keys.Count();
|
||||
csave.Begin_Chunk(CURVE1D_CHUNK_VARIABLES);
|
||||
WRITE_MICRO_CHUNK(csave,CURVE1D_VARIABLE_ISLOOPING,IsLooping);
|
||||
WRITE_MICRO_CHUNK(csave,CURVE1D_VARIABLE_KEYCOUNT,keycount);
|
||||
csave.End_Chunk();
|
||||
|
||||
// Saving the keys, Note that if the format of a key changes we'll
|
||||
// need a new chunk. (I didn't wrap each variable in its own chunk)
|
||||
csave.Begin_Chunk(CURVE1D_CHUNK_KEYS);
|
||||
for (int i=0; i<keycount; i++) {
|
||||
csave.Write(&(Keys[i].Point),sizeof(Keys[i].Point));
|
||||
csave.Write(&(Keys[i].Time),sizeof(Keys[i].Time));
|
||||
csave.Write(&(Keys[i].Extra),sizeof(Keys[i].Extra));
|
||||
}
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Curve1DClass::Load(ChunkLoadClass & cload)
|
||||
{
|
||||
int i;
|
||||
int keycount = 0;
|
||||
KeyClass newkey;
|
||||
|
||||
// reset the curve
|
||||
Keys.Delete_All();
|
||||
|
||||
// read in the chunks
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case CURVE1D_CHUNK_VARIABLES:
|
||||
|
||||
while (cload.Open_Micro_Chunk()) {
|
||||
switch(cload.Cur_Micro_Chunk_ID()) {
|
||||
READ_MICRO_CHUNK(cload,CURVE1D_VARIABLE_ISLOOPING,IsLooping);
|
||||
READ_MICRO_CHUNK(cload,CURVE1D_VARIABLE_KEYCOUNT,keycount);
|
||||
}
|
||||
cload.Close_Micro_Chunk();
|
||||
}
|
||||
break;
|
||||
|
||||
case CURVE1D_CHUNK_KEYS:
|
||||
for (i=0; i<keycount; i++) {
|
||||
cload.Read(&(newkey.Point),sizeof(newkey.Point));
|
||||
cload.Read(&(newkey.Time),sizeof(newkey.Time));
|
||||
cload.Read(&(newkey.Extra),sizeof(newkey.Extra));
|
||||
Keys.Add(newkey);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
**
|
||||
** LinearCurve1DClass, linearly interpolates the keys
|
||||
**
|
||||
***********************************************************************************************/
|
||||
void LinearCurve1DClass::Evaluate(float time,float * set_val)
|
||||
{
|
||||
if (!IsLooping) {
|
||||
if (time < Keys[0].Time) {
|
||||
*set_val = Keys[0].Point;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time >= Keys[Keys.Count() - 1].Time) {
|
||||
*set_val = Keys[Keys.Count() - 1].Point;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int i0,i1;
|
||||
float t;
|
||||
Find_Interval(time,&i0,&i1,&t);
|
||||
|
||||
*set_val = Keys[i0].Point + t * (Keys[i1].Point - Keys[i0].Point);
|
||||
}
|
||||
|
||||
const PersistFactoryClass & LinearCurve1DClass::Get_Factory(void) const
|
||||
{
|
||||
return _LinearCurve1DFactory;
|
||||
}
|
||||
|
||||
bool LinearCurve1DClass::Save(ChunkSaveClass & csave)
|
||||
{
|
||||
csave.Begin_Chunk(LINEARCURVE1D_CHUNK_CURVE1D);
|
||||
Curve1DClass::Save(csave);
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LinearCurve1DClass::Load(ChunkLoadClass & cload)
|
||||
{
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case LINEARCURVE1D_CHUNK_CURVE1D:
|
||||
Curve1DClass::Load(cload);
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
179
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/curve.h
Normal file
179
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/curve.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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:: /VSS_Sync/wwmath/curve.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 6/13/01 2:18p $*
|
||||
* *
|
||||
* $Revision:: 8 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef CURVE_H
|
||||
#define CURVE_H
|
||||
|
||||
#ifndef ALWAYS_H
|
||||
#include "always.h"
|
||||
#endif
|
||||
|
||||
#ifndef VECTOR_H
|
||||
#include "vector.h"
|
||||
#endif
|
||||
|
||||
#ifndef VECTOR3_H
|
||||
#include "vector3.h"
|
||||
#endif
|
||||
|
||||
#ifndef PERSIST_H
|
||||
#include "persist.h"
|
||||
#endif
|
||||
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
|
||||
|
||||
class Curve3DClass : public PersistClass
|
||||
{
|
||||
public:
|
||||
|
||||
Curve3DClass(void);
|
||||
Curve3DClass(const Curve3DClass & that);
|
||||
virtual ~Curve3DClass(void);
|
||||
Curve3DClass & operator = (const Curve3DClass & that);
|
||||
|
||||
virtual void Evaluate(float time,Vector3 * set_val) = 0;
|
||||
virtual bool Is_Looping(void);
|
||||
virtual void Set_Looping(bool onoff);
|
||||
virtual int Key_Count(void);
|
||||
virtual void Get_Key(int i,Vector3 * set_point,float * set_t);
|
||||
virtual void Set_Key(int i,const Vector3 & point);
|
||||
virtual int Add_Key(const Vector3 & point,float t);
|
||||
virtual void Remove_Key(int i);
|
||||
virtual void Clear_Keys(void);
|
||||
float Get_Start_Time(void);
|
||||
float Get_End_Time(void);
|
||||
|
||||
// persistant object support
|
||||
virtual bool Save (ChunkSaveClass &csave);
|
||||
virtual bool Load (ChunkLoadClass &cload);
|
||||
|
||||
protected:
|
||||
|
||||
void Find_Interval(float time,int * i0,int * i1,float * t);
|
||||
|
||||
class KeyClass
|
||||
{
|
||||
public:
|
||||
Vector3 Point;
|
||||
float Time;
|
||||
bool operator == (const KeyClass & that) { return ((Point == that.Point) && (Time == that.Time)); }
|
||||
bool operator != (const KeyClass & that) { return !KeyClass::operator==(that); }
|
||||
};
|
||||
|
||||
bool IsLooping;
|
||||
DynamicVectorClass<KeyClass> Keys;
|
||||
};
|
||||
|
||||
|
||||
class LinearCurve3DClass : public Curve3DClass
|
||||
{
|
||||
public:
|
||||
virtual void Evaluate(float time,Vector3 * set_val);
|
||||
|
||||
// persistant object support
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** 1-Dimensional curve classes.
|
||||
*/
|
||||
class Curve1DClass : public PersistClass
|
||||
{
|
||||
public:
|
||||
|
||||
Curve1DClass(void);
|
||||
Curve1DClass(const Curve1DClass & that);
|
||||
virtual ~Curve1DClass(void);
|
||||
Curve1DClass & operator = (const Curve1DClass & that);
|
||||
|
||||
virtual void Evaluate(float time,float * set_val) = 0;
|
||||
virtual bool Is_Looping(void);
|
||||
virtual void Set_Looping(bool onoff);
|
||||
virtual int Key_Count(void);
|
||||
virtual void Get_Key(int i,float * set_point,float * set_t,unsigned int * extra=NULL);
|
||||
virtual void Set_Key(int i,float point,unsigned int extra=0);
|
||||
virtual int Add_Key(float point,float t,unsigned int extra=0);
|
||||
virtual void Remove_Key(int i);
|
||||
virtual void Clear_Keys(void);
|
||||
float Get_Start_Time(void);
|
||||
float Get_End_Time(void);
|
||||
|
||||
// persistant object support
|
||||
virtual bool Save (ChunkSaveClass &csave);
|
||||
virtual bool Load (ChunkLoadClass &cload);
|
||||
|
||||
protected:
|
||||
|
||||
void Find_Interval(float time,int * i0,int * i1,float * t);
|
||||
|
||||
class KeyClass
|
||||
{
|
||||
public:
|
||||
float Point;
|
||||
float Time;
|
||||
unsigned int Extra;
|
||||
bool operator == (const KeyClass & that) { return ((Point == that.Point) && (Time == that.Time) && (Extra == that.Extra)); }
|
||||
bool operator != (const KeyClass & that) { return !KeyClass::operator==(that); }
|
||||
};
|
||||
|
||||
bool IsLooping;
|
||||
DynamicVectorClass<KeyClass> Keys;
|
||||
};
|
||||
|
||||
|
||||
class LinearCurve1DClass : public Curve1DClass
|
||||
{
|
||||
public:
|
||||
virtual void Evaluate(float time,float * set_val);
|
||||
|
||||
// persistant object support
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
};
|
||||
|
||||
|
||||
#endif //CURVE_H
|
||||
373
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/euler.cpp
Normal file
373
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/euler.cpp
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/euler.cpp 5 4/27/01 11:51a Jani_p $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G Math Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/wwmath/euler.cpp $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 4/23/01 6:08p $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* EulerAnglesClass::EulerAnglesClass -- constructor *
|
||||
* EulerAnglesClass::Get_Angle -- returns angle 'i' of the euler angles *
|
||||
* EulerAnglesClass::From_Matrix -- computes the equivalent euler angles for the given matrix*
|
||||
* EulerAnglesClass::To_Matrix -- Builds a matrix from the given euler angles *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "euler.h"
|
||||
#include <float.h>
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
|
||||
There are 24 possible conventions for Euler angles. They can
|
||||
be designated by:
|
||||
|
||||
EulerAxis = Axis used initially
|
||||
EulerParity = parity of axis permutation (even = x,y,z)
|
||||
EulerRepeat = is last axis a repeat of the initial axis?
|
||||
EulerFrame = frame from which axes are taken (rotating or static)
|
||||
|
||||
For example, in this system an euler angle convention of:
|
||||
|
||||
Rotate_X(a0);
|
||||
Rotate_Y(a1);
|
||||
Rotate_Z(a2);
|
||||
|
||||
would be described as EulerOrderXYZr.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#define EULER_FRAME_STATIC 0x00000000
|
||||
#define EULER_FRAME_ROTATING 0x00000001
|
||||
#define EULER_FRAME(order) ((unsigned)(order) & 1)
|
||||
|
||||
#define EULER_REPEAT_NO 0x00000000
|
||||
#define EULER_REPEAT_YES 0x00000001
|
||||
#define EULER_REPEAT(order) (((unsigned)(order) >> 1) & 1)
|
||||
|
||||
#define EULER_PARITY_EVEN 0x00000000
|
||||
#define EULER_PARITY_ODD 0x00000001
|
||||
#define EULER_PARITY(order) (((unsigned)(order) >> 2) & 1)
|
||||
|
||||
#define EULER_BUILD_ORDER(i,p,r,f) (((((((i) << 1) + (p)) << 1) + (r)) << 1) + (f))
|
||||
|
||||
|
||||
/* static axes */
|
||||
int EulerOrderXYZs = EULER_BUILD_ORDER(0, EULER_PARITY_EVEN, EULER_REPEAT_NO, EULER_FRAME_STATIC);
|
||||
int EulerOrderXYXs = EULER_BUILD_ORDER(0, EULER_PARITY_EVEN, EULER_REPEAT_YES, EULER_FRAME_STATIC);
|
||||
int EulerOrderXZYs = EULER_BUILD_ORDER(0, EULER_PARITY_ODD, EULER_REPEAT_NO, EULER_FRAME_STATIC);
|
||||
int EulerOrderXZXs = EULER_BUILD_ORDER(0, EULER_PARITY_ODD, EULER_REPEAT_YES, EULER_FRAME_STATIC);
|
||||
int EulerOrderYZXs = EULER_BUILD_ORDER(1, EULER_PARITY_EVEN, EULER_REPEAT_NO, EULER_FRAME_STATIC);
|
||||
int EulerOrderYZYs = EULER_BUILD_ORDER(1, EULER_PARITY_EVEN, EULER_REPEAT_YES, EULER_FRAME_STATIC);
|
||||
int EulerOrderYXZs = EULER_BUILD_ORDER(1, EULER_PARITY_ODD, EULER_REPEAT_NO, EULER_FRAME_STATIC);
|
||||
int EulerOrderYXYs = EULER_BUILD_ORDER(1, EULER_PARITY_ODD, EULER_REPEAT_YES, EULER_FRAME_STATIC);
|
||||
int EulerOrderZXYs = EULER_BUILD_ORDER(2, EULER_PARITY_EVEN, EULER_REPEAT_NO, EULER_FRAME_STATIC);
|
||||
int EulerOrderZXZs = EULER_BUILD_ORDER(2, EULER_PARITY_EVEN, EULER_REPEAT_YES, EULER_FRAME_STATIC);
|
||||
int EulerOrderZYXs = EULER_BUILD_ORDER(2, EULER_PARITY_ODD, EULER_REPEAT_NO, EULER_FRAME_STATIC);
|
||||
int EulerOrderZYZs = EULER_BUILD_ORDER(2, EULER_PARITY_ODD, EULER_REPEAT_YES, EULER_FRAME_STATIC);
|
||||
|
||||
/* rotating axes */
|
||||
int EulerOrderZYXr = EULER_BUILD_ORDER(0, EULER_PARITY_EVEN, EULER_REPEAT_NO, EULER_FRAME_ROTATING);
|
||||
int EulerOrderXYXr = EULER_BUILD_ORDER(0, EULER_PARITY_EVEN, EULER_REPEAT_YES, EULER_FRAME_ROTATING);
|
||||
int EulerOrderYZXr = EULER_BUILD_ORDER(0, EULER_PARITY_ODD, EULER_REPEAT_NO, EULER_FRAME_ROTATING);
|
||||
int EulerOrderXZXr = EULER_BUILD_ORDER(0, EULER_PARITY_ODD, EULER_REPEAT_YES, EULER_FRAME_ROTATING);
|
||||
int EulerOrderXZYr = EULER_BUILD_ORDER(1, EULER_PARITY_EVEN, EULER_REPEAT_NO, EULER_FRAME_ROTATING);
|
||||
int EulerOrderYZYr = EULER_BUILD_ORDER(1, EULER_PARITY_EVEN, EULER_REPEAT_YES, EULER_FRAME_ROTATING);
|
||||
int EulerOrderZXYr = EULER_BUILD_ORDER(1, EULER_PARITY_ODD, EULER_REPEAT_NO, EULER_FRAME_ROTATING);
|
||||
int EulerOrderYXYr = EULER_BUILD_ORDER(1, EULER_PARITY_ODD, EULER_REPEAT_YES, EULER_FRAME_ROTATING);
|
||||
int EulerOrderYXZr = EULER_BUILD_ORDER(2, EULER_PARITY_EVEN, EULER_REPEAT_NO, EULER_FRAME_ROTATING);
|
||||
int EulerOrderZXZr = EULER_BUILD_ORDER(2, EULER_PARITY_EVEN, EULER_REPEAT_YES, EULER_FRAME_ROTATING);
|
||||
int EulerOrderXYZr = EULER_BUILD_ORDER(2, EULER_PARITY_ODD, EULER_REPEAT_NO, EULER_FRAME_ROTATING);
|
||||
int EulerOrderZYZr = EULER_BUILD_ORDER(2, EULER_PARITY_ODD, EULER_REPEAT_YES, EULER_FRAME_ROTATING);
|
||||
|
||||
|
||||
#define EULER_SAFE "\000\001\002\000"
|
||||
#define EULER_NEXT "\001\002\000\001"
|
||||
|
||||
#define EULER_AXIS_I(order) ((int)(EULER_SAFE[(((unsigned)(ord)>>3) & 3)]))
|
||||
#define EULER_AXIS_J(order) ((int)(EULER_NEXT[EULER_AXIS_I(order) + (EULER_PARITY(order) == EULER_PARITY_ODD)]))
|
||||
#define EULER_AXIS_K(order) ((int)(EULER_NEXT[EULER_AXIS_I(order) + (EULER_PARITY(order) != EULER_PARITY_ODD)]))
|
||||
#define EULER_AXIS_H(order) ((EULER_REPEAT(order) == EULER_REPEAT_NO) ? EULER_AXIS_K(order) : EULER_AXIS_I(order))
|
||||
|
||||
|
||||
|
||||
/* local functions */
|
||||
static void _euler_unpack_order(int order,int &i,int &j,int &k,int &h,int &n,int &s,int &f);
|
||||
static int _euler_axis_i(int order);
|
||||
static int _euler_axis_j(int order);
|
||||
static int _euler_axis_k(int order);
|
||||
static int _euler_axis_h(int order);
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* EulerAnglesClass::EulerAnglesClass -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
EulerAnglesClass::EulerAnglesClass(const Matrix3D & M,int order)
|
||||
{
|
||||
this->From_Matrix(M,order);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* EulerAnglesClass::Get_Angle -- returns angle 'i' of the euler angles *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
double EulerAnglesClass::Get_Angle(int i)
|
||||
{
|
||||
return Angle[i];
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* EulerAnglesClass::From_Matrix -- computes the equivalent euler angles for the given matrix *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void EulerAnglesClass::From_Matrix(const Matrix3D & M, int order)
|
||||
{
|
||||
int i,j,k,h,n,s,f;
|
||||
|
||||
Order = order;
|
||||
_euler_unpack_order(order,i,j,k,h,n,s,f);
|
||||
|
||||
if (s == EULER_REPEAT_YES) {
|
||||
double sy = sqrt(M[i][j]*M[i][j] + M[i][k]*M[i][k]);
|
||||
|
||||
if (sy > 16*FLT_EPSILON) {
|
||||
|
||||
Angle[0] = WWMath::Atan2(M[i][j],M[i][k]);
|
||||
Angle[1] = WWMath::Atan2(sy,M[i][i]);
|
||||
Angle[2] = WWMath::Atan2(M[j][i],-M[k][i]);
|
||||
|
||||
} else {
|
||||
|
||||
Angle[0] = WWMath::Atan2(-M[j][k],M[j][j]);
|
||||
Angle[1] = WWMath::Atan2(sy,M[i][i]);
|
||||
Angle[2] = 0.0;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
double cy = sqrt(M[i][i]*M[i][i] + M[j][i]*M[j][i]);
|
||||
|
||||
if (cy > 16*FLT_EPSILON) {
|
||||
|
||||
Angle[0] = WWMath::Atan2(M[k][j],M[k][k]);
|
||||
Angle[1] = WWMath::Atan2(-M[k][i],cy);
|
||||
Angle[2] = WWMath::Atan2(M[j][i],M[i][i]);
|
||||
|
||||
} else {
|
||||
|
||||
Angle[0] = WWMath::Atan2(-M[j][k],M[j][j]);
|
||||
Angle[1] = WWMath::Atan2(-M[k][i],cy);
|
||||
Angle[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (n==EULER_PARITY_ODD) { Angle[0] = -Angle[0]; Angle[1] = -Angle[1]; Angle[2] = -Angle[2]; }
|
||||
if (f==EULER_FRAME_ROTATING) { double t = Angle[0]; Angle[0] = Angle[2]; Angle[2] = t; }
|
||||
|
||||
// Trying to "clean" up the eulers, special cased for XYZr
|
||||
if (order == EulerOrderXYZr) {
|
||||
|
||||
const double PI = 3.141592654;
|
||||
|
||||
double x2 = PI + Angle[0];
|
||||
double y2 = PI - Angle[1];
|
||||
double z2 = PI + Angle[2];
|
||||
|
||||
if (x2 > PI) {
|
||||
x2 = x2 - 2*PI;
|
||||
}
|
||||
|
||||
if (y2 > PI) {
|
||||
y2 = y2 - 2*PI;
|
||||
}
|
||||
|
||||
if (z2 > PI) {
|
||||
z2 = z2 - 2*PI;
|
||||
}
|
||||
|
||||
double mag0 = Angle[0]*Angle[0] + Angle[1]*Angle[1] + Angle[2]*Angle[2];
|
||||
double mag1 = x2*x2 + y2*y2 + z2*z2;
|
||||
|
||||
if (mag1 < mag0) {
|
||||
Angle[0] = x2;
|
||||
Angle[1] = y2;
|
||||
Angle[2] = z2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* EulerAnglesClass::To_Matrix -- Builds a matrix from the given euler angles *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void EulerAnglesClass::To_Matrix(Matrix3D & M)
|
||||
{
|
||||
M.Make_Identity();
|
||||
|
||||
double a0,a1,a2;
|
||||
double ti,tj,th,ci,cj,ch,si,sj,sh,cc,cs,sc,ss;
|
||||
int i,j,k,h,n,s,f;
|
||||
|
||||
a0 = Angle[0];
|
||||
a1 = Angle[1];
|
||||
a2 = Angle[2];
|
||||
|
||||
_euler_unpack_order(Order,i,j,k,h,n,s,f);
|
||||
if (f == EULER_FRAME_ROTATING) {
|
||||
double t = a0; a0 = a2; a2 = t;
|
||||
}
|
||||
|
||||
if (n == EULER_PARITY_ODD) {
|
||||
a0 = -a0; a1 = -a1; a2 = -a2;
|
||||
}
|
||||
|
||||
ti = a0; tj = a1; th = a2;
|
||||
ci = WWMath::Cos(ti); cj = WWMath::Cos(tj); ch = WWMath::Cos(th);
|
||||
si = WWMath::Sin(ti); sj = WWMath::Sin(tj); sh = WWMath::Sin(th);
|
||||
|
||||
cc = ci*ch;
|
||||
cs = ci*sh;
|
||||
sc = si*ch;
|
||||
ss = si*sh;
|
||||
|
||||
if (s == EULER_REPEAT_YES) {
|
||||
|
||||
M[i][i] = (float)(cj); M[i][j] = (float)(sj*si); M[i][k] = (float)(sj*ci);
|
||||
M[j][i] = (float)(sj*sh); M[j][j] = (float)(-cj*ss+cc); M[j][k] = (float)(-cj*cs-sc);
|
||||
M[k][i] = (float)(-sj*ch); M[k][j] = (float)(cj*sc+cs); M[k][k] = (float)(cj*cc-ss);
|
||||
|
||||
} else {
|
||||
|
||||
M[i][i] = (float)(cj*ch); M[i][j] = (float)(sj*sc-cs); M[i][k] = (float)(sj*cc+ss);
|
||||
M[j][i] = (float)(cj*sh); M[j][j] = (float)(sj*ss+cc); M[j][k] = (float)(sj*cs-sc);
|
||||
M[k][i] = (float)(-sj); M[k][j] = (float)(cj*si); M[k][k] = (float)(cj*ci);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Local functions
|
||||
*/
|
||||
|
||||
static int _euler_safe[] = { 0,1,2,0 };
|
||||
static int _euler_next[] = { 1,2,0,1 };
|
||||
|
||||
int _euler_axis_i(int order)
|
||||
{
|
||||
return _euler_safe[ (order>>3) & 3 ];
|
||||
}
|
||||
|
||||
int _euler_axis_j(int order)
|
||||
{
|
||||
int index = _euler_axis_i(order);
|
||||
if (EULER_PARITY(order) == 1) {
|
||||
index++;
|
||||
}
|
||||
|
||||
return _euler_next[ index ];
|
||||
}
|
||||
|
||||
int _euler_axis_k(int order)
|
||||
{
|
||||
int index = _euler_axis_i(order);
|
||||
if (EULER_PARITY(order) != 1) {
|
||||
index++;
|
||||
}
|
||||
|
||||
return _euler_next[ index ];
|
||||
}
|
||||
|
||||
int _euler_axis_h(int order)
|
||||
{
|
||||
if (EULER_REPEAT(order) == 1) {
|
||||
return _euler_axis_k(order);
|
||||
} else {
|
||||
return _euler_axis_i(order);
|
||||
}
|
||||
}
|
||||
|
||||
void _euler_unpack_order(int order,int &i,int &j,int &k,int &h,int &n,int &s,int &f)
|
||||
{
|
||||
|
||||
f = order & 1;
|
||||
order >>= 1;
|
||||
|
||||
s = order & 1;
|
||||
order >>= 1;
|
||||
|
||||
n = order & 1;
|
||||
order >>= 1;
|
||||
|
||||
i = _euler_safe[order & 3];
|
||||
j = _euler_next[i+n];
|
||||
k = _euler_next[i+1-n];
|
||||
h = (s ? k : i);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
127
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/euler.h
Normal file
127
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/euler.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/euler.h 5 5/05/01 5:48p Jani_p $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando / G Math Library *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/wwmath/euler.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 5/04/01 8:37p $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef EULER_H
|
||||
#define EULER_H
|
||||
|
||||
#include "always.h"
|
||||
#include "matrix3d.h"
|
||||
#include "quat.h"
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
|
||||
Euler Order Types
|
||||
|
||||
When creating an EulerAngles object, use one of the below
|
||||
constants to describe the axis convention.
|
||||
|
||||
XYZ - order of the axes
|
||||
s/r - whether the rotations are applied to a static or
|
||||
rotating frame.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* static axes */
|
||||
extern int EulerOrderXYZs;
|
||||
extern int EulerOrderXYXs;
|
||||
extern int EulerOrderXZYs;
|
||||
extern int EulerOrderXZXs;
|
||||
extern int EulerOrderYZXs;
|
||||
extern int EulerOrderYZYs;
|
||||
extern int EulerOrderYXZs;
|
||||
extern int EulerOrderYXYs;
|
||||
extern int EulerOrderZXYs;
|
||||
extern int EulerOrderZXZs;
|
||||
extern int EulerOrderZYXs;
|
||||
extern int EulerOrderZYZs;
|
||||
|
||||
/* rotating axes */
|
||||
extern int EulerOrderXYZr;
|
||||
extern int EulerOrderXYXr;
|
||||
extern int EulerOrderXZYr;
|
||||
extern int EulerOrderXZXr;
|
||||
extern int EulerOrderYZXr;
|
||||
extern int EulerOrderYZYr;
|
||||
extern int EulerOrderYXZr;
|
||||
extern int EulerOrderYXYr;
|
||||
extern int EulerOrderZXYr;
|
||||
extern int EulerOrderZXZr;
|
||||
extern int EulerOrderZYXr;
|
||||
extern int EulerOrderZYZr;
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
|
||||
EulerAnglesClass
|
||||
|
||||
The purpose for this class is mainly for conversion. You can
|
||||
choose a convention for the order of your rotations and then
|
||||
convert matrices into a set of euler angles. You don't really
|
||||
want to use this at run-time to convert matrices into angles.
|
||||
|
||||
The guts of this implementation is based on the article in Graphics
|
||||
Gems IV by Ken Shoemake. The original article is on page 222.
|
||||
|
||||
*********************************************************************/
|
||||
class EulerAnglesClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
EulerAnglesClass(void) : Order(0) { Angle[0] = 0.0; Angle[1] = 0.0; Angle[2] = 0.0; };
|
||||
EulerAnglesClass(const Matrix3D & from,int order);
|
||||
void From_Matrix(const Matrix3D & from,int order);
|
||||
void To_Matrix(Matrix3D & M);
|
||||
|
||||
double Get_Angle(int i);
|
||||
|
||||
private:
|
||||
|
||||
double Angle[3];
|
||||
int Order;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /*EULER_H*/
|
||||
168
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/frustum.cpp
Normal file
168
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/frustum.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/frustum.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 4/01/01 12:47p $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* FrustumClass::Init -- Initialize a frustum object *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "frustum.h"
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* FrustumClass::Init -- Initialize a frustum object *
|
||||
* *
|
||||
* This function initializes a frustum from the description of a camera *
|
||||
* *
|
||||
* INPUT: *
|
||||
* camera - camera transform, note that the camera looks down the -Z axis *
|
||||
* vpmin - min corner of the z=-1.0 view plane (not necessarily the near clip plane) *
|
||||
* vpmax - max corner of the z=-1.0 view plane (not necessarily the near clip plane) *
|
||||
* znear - near clip plane (should be negative, negated if it is not) *
|
||||
* zfar - far clip plane (should be negative, negated if it is not) *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* The vpmin and vpmax variables are the min and max of a view-plane at z=-1.0 *
|
||||
* *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 2/17/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void FrustumClass::Init
|
||||
(
|
||||
const Matrix3D & camera,
|
||||
const Vector2 & vpmin,
|
||||
const Vector2 & vpmax,
|
||||
float znear,
|
||||
float zfar
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Store the camera transform
|
||||
CameraTransform = camera;
|
||||
|
||||
// Forward is negative Z in our viewspace coordinate system.
|
||||
// Just flip the sign if the user passed in positive values.
|
||||
if ((znear > 0.0f) && (zfar > 0.0f)) {
|
||||
znear = -znear;
|
||||
zfar = -zfar;
|
||||
}
|
||||
|
||||
// Calculate the corners of the camera frustum.
|
||||
// Generate the camera-space frustum corners by linearly
|
||||
// extrapolating the viewplane to the near and far z clipping planes.
|
||||
|
||||
// The camera frustum corners are defined in the following order:
|
||||
// When looking at the frustum from the position of the camera, the near four corners are
|
||||
// numbered: upper left 0, upper right 1, lower left 2, lower right 3. The far plane's
|
||||
// Frustum corners are numbered from 4 to 7 in an analogous fashion.
|
||||
// (remember: the camera space has x going to the right, y up and z backwards).
|
||||
|
||||
//calculate a proper z-vector assuming our right-handed coordinate system
|
||||
Vector3 zv;
|
||||
Vector3::Cross_Product(CameraTransform.Get_X_Vector(),CameraTransform.Get_Y_Vector(),&zv);
|
||||
|
||||
//compare correct z-vector with the one in the camera matrix. If they point in
|
||||
//opposite directions, we have a reflected camera matrix.
|
||||
if (Vector3::Dot_Product(CameraTransform.Get_Z_Vector(),zv) < 0)
|
||||
{ //flip the frustum corners horizontally for a reflected matrix
|
||||
Corners[1].Set(vpmin.X, vpmax.Y, 1.0);
|
||||
Corners[5] = Corners[1];
|
||||
Corners[1] *= znear;
|
||||
Corners[5] *= zfar;
|
||||
Corners[0].Set(vpmax.X, vpmax.Y, 1.0);
|
||||
Corners[4] = Corners[0];
|
||||
Corners[0] *= znear;
|
||||
Corners[4] *= zfar;
|
||||
Corners[3].Set(vpmin.X, vpmin.Y, 1.0);
|
||||
Corners[7] = Corners[3];
|
||||
Corners[3] *= znear;
|
||||
Corners[7] *= zfar;
|
||||
Corners[2].Set(vpmax.X, vpmin.Y, 1.0);
|
||||
Corners[6] = Corners[2];
|
||||
Corners[2] *= znear;
|
||||
Corners[6] *= zfar;
|
||||
}
|
||||
else
|
||||
{ //normal camera
|
||||
Corners[0].Set(vpmin.X, vpmax.Y, 1.0);
|
||||
Corners[4] = Corners[0];
|
||||
Corners[0] *= znear;
|
||||
Corners[4] *= zfar;
|
||||
Corners[1].Set(vpmax.X, vpmax.Y, 1.0);
|
||||
Corners[5] = Corners[1];
|
||||
Corners[1] *= znear;
|
||||
Corners[5] *= zfar;
|
||||
Corners[2].Set(vpmin.X, vpmin.Y, 1.0);
|
||||
Corners[6] = Corners[2];
|
||||
Corners[2] *= znear;
|
||||
Corners[6] *= zfar;
|
||||
Corners[3].Set(vpmax.X, vpmin.Y, 1.0);
|
||||
Corners[7] = Corners[3];
|
||||
Corners[3] *= znear;
|
||||
Corners[7] *= zfar;
|
||||
}
|
||||
|
||||
|
||||
// Transform the eight corners of the view frustum from camera space to world space.
|
||||
for (i = 0; i < 8; i++) {
|
||||
Matrix3D::Transform_Vector(CameraTransform, Corners[i], &(Corners[i]));
|
||||
}
|
||||
|
||||
// Create the six frustum bounding planes from the eight corner Corners.
|
||||
// The bounding planes are oriented so that their normals point outward
|
||||
PlaneClass frustum_planes[6];
|
||||
Planes[0].Set(Corners[0], Corners[3], Corners[1]); // near
|
||||
Planes[1].Set(Corners[0], Corners[5], Corners[4]); // bottom
|
||||
Planes[2].Set(Corners[0], Corners[6], Corners[2]); // right
|
||||
Planes[3].Set(Corners[2], Corners[7], Corners[3]); // top
|
||||
Planes[4].Set(Corners[1], Corners[7], Corners[5]); // left
|
||||
Planes[5].Set(Corners[4], Corners[7], Corners[6]); // far
|
||||
|
||||
// find the bounding box of the entire frustum (may be used for sloppy quick rejection)
|
||||
BoundMin = BoundMax = Corners[0];
|
||||
|
||||
for (i=1; i<8;i++) {
|
||||
if (Corners[i].X < BoundMin.X) BoundMin.X = Corners[i].X;
|
||||
if (Corners[i].X > BoundMax.X) BoundMax.X = Corners[i].X;
|
||||
|
||||
if (Corners[i].Y < BoundMin.Y) BoundMin.Y = Corners[i].Y;
|
||||
if (Corners[i].Y > BoundMax.Y) BoundMax.Y = Corners[i].Y;
|
||||
|
||||
if (Corners[i].Z < BoundMin.Z) BoundMin.Z = Corners[i].Z;
|
||||
if (Corners[i].Z > BoundMax.Z) BoundMax.Z = Corners[i].Z;
|
||||
}
|
||||
}
|
||||
|
||||
73
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/frustum.h
Normal file
73
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/frustum.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/frustum.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 3/29/00 10:20a $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef FRUSTUM_H
|
||||
#define FRUSTUM_H
|
||||
|
||||
#include "vector3.h"
|
||||
#include "plane.h"
|
||||
|
||||
|
||||
class FrustumClass
|
||||
{
|
||||
public:
|
||||
void Init( const Matrix3D & camera,
|
||||
const Vector2 & viewport_min,
|
||||
const Vector2 & viewport_max,
|
||||
float znear,
|
||||
float zfar );
|
||||
|
||||
const Vector3 & Get_Bound_Min(void) const { return BoundMin; }
|
||||
const Vector3 & Get_Bound_Max(void) const { return BoundMax; }
|
||||
|
||||
public:
|
||||
|
||||
Matrix3D CameraTransform;
|
||||
PlaneClass Planes[6];
|
||||
Vector3 Corners[8];
|
||||
Vector3 BoundMin;
|
||||
Vector3 BoundMax;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
1024
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/gridcull.cpp
Normal file
1024
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/gridcull.cpp
Normal file
File diff suppressed because it is too large
Load Diff
706
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/gridcull.h
Normal file
706
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/gridcull.h
Normal file
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/gridcull.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 5/10/01 10:42a $*
|
||||
* *
|
||||
* $Revision:: 14 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* GridCullSystemClass::clamp_indices_to_grid -- constrains indices to be a valid location *
|
||||
* GridCullSystemClass::map_point_to_cell -- determines which cell the point is in *
|
||||
* GridCullSystemClass::map_point_to_address -- determines the address of a point in the gri *
|
||||
* GridCullSystemClass::map_indices_to_address -- computes the address for given index tripl *
|
||||
* GridCullSystemClass::total_cell_count -- returns the total number of cells in the grid *
|
||||
* GridCullSystemClass::compute_box -- computes the bounding box for a grid cell *
|
||||
* GridCullSystemClass::compute_box -- computes bounding box for a range of grid cells *
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given range *
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given line segment *
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given box *
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given oriented box *
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given frustum *
|
||||
* GridCullSystemClass::VolumeStruct::VolumeStruct -- constructor *
|
||||
* GridCullSystemClass::VolumeStruct::VolumeStruct -- constructor *
|
||||
* GridCullSystemClass::VolumeStruct::Is_Leaf -- check if volume is a leaf *
|
||||
* GridCullSystemClass::VolumeStruct::Is_Empty -- check if volume is empty (or invalid) *
|
||||
* GridCullSystemClass::VolumeStruct::Split -- split this volume *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "cullsys.h"
|
||||
#include "mempool.h"
|
||||
#include "frustum.h"
|
||||
#include "aabox.h"
|
||||
#include "lineseg.h"
|
||||
#include "obbox.h"
|
||||
#include <string.h>
|
||||
|
||||
class ChunkLoadClass;
|
||||
class ChunkSaveClass;
|
||||
|
||||
/*
|
||||
** GridCullSystemClass
|
||||
** This is a culling system designed for dynamic objects (objects which are moving or
|
||||
** changing bounding box size). It features O(1) insertion as opposed to
|
||||
** the AABTree, QuadTree, or Octree insertion times which are O(logn). It's disadvantages
|
||||
** compared to the above mentioned systems are that it must uniformly divide space. The
|
||||
** AABTree conforms to the geometry placed in it and can therefore cull things more
|
||||
** efficiently. In actual use, this system is like an AAB-tree which is uniformly subdivided,
|
||||
** its just that we can jump straight to the leaves of the tree for insertion...
|
||||
**
|
||||
** The bounding volume for each grid cell is considered to be the volume of the cell, expanded
|
||||
** by the maximum object size. Inserting an object into the grid is a matter of determining
|
||||
** which cell its center point is in. Objects which are larger than the maximum size are
|
||||
** allowed but they are simply put into a linked list which is iterated with each call to
|
||||
** the culling system (linearly culled rather than logarithmic...)
|
||||
*/
|
||||
class GridCullSystemClass : public CullSystemClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
GridCullSystemClass(void);
|
||||
~GridCullSystemClass(void);
|
||||
|
||||
virtual void Collect_Objects(const Vector3 & point);
|
||||
virtual void Collect_Objects(const AABoxClass & box);
|
||||
virtual void Collect_Objects(const OBBoxClass & box);
|
||||
virtual void Collect_Objects(const FrustumClass & frustum);
|
||||
|
||||
virtual void Re_Partition(const Vector3 & min,const Vector3 & max,float objdim);
|
||||
virtual void Update_Culling(CullableClass * obj);
|
||||
|
||||
virtual void Load(ChunkLoadClass & cload);
|
||||
virtual void Save(ChunkSaveClass & csave);
|
||||
|
||||
virtual int Get_Object_Count (void) const { return ObjCount; }
|
||||
|
||||
/*
|
||||
** Statistics
|
||||
*/
|
||||
struct StatsStruct
|
||||
{
|
||||
int NodeCount;
|
||||
int NodesAccepted;
|
||||
int NodesTriviallyAccepted;
|
||||
int NodesRejected;
|
||||
};
|
||||
|
||||
void Reset_Statistics(void);
|
||||
const StatsStruct & Get_Statistics(void);
|
||||
|
||||
void Get_Min_Cell_Size (Vector3 &size) const { size = MinCellSize; }
|
||||
void Set_Min_Cell_Size (const Vector3 &size) { MinCellSize = size; }
|
||||
|
||||
int Get_Termination_Count (void) const { return TerminationCellCount; }
|
||||
void Set_Termination_Count (int count) { TerminationCellCount = count; }
|
||||
|
||||
protected:
|
||||
|
||||
void Collect_And_Unlink_All(void);
|
||||
void Add_Object_Internal(CullableClass * obj);
|
||||
void Remove_Object_Internal(CullableClass * obj);
|
||||
|
||||
enum
|
||||
{
|
||||
TERMINATION_CELL_COUNT = 16384, // algorithm terminates if we ever have more than this many cells.
|
||||
UNGRIDDED_ADDRESS = 0xFFFFFFFF // address given to objs that didn't fit in grid
|
||||
};
|
||||
|
||||
// Constants which control the division of space:
|
||||
Vector3 MinCellSize; // min dimensions for a cell (don't go below this...)
|
||||
float MaxObjExtent; // max extent/radius (objects bigger than this are just put in a list)
|
||||
int TerminationCellCount;
|
||||
|
||||
// Constants that define the division of space
|
||||
Vector3 Origin;
|
||||
Vector3 CellDim;
|
||||
Vector3 OOCellDim;
|
||||
int CellCount[3];
|
||||
|
||||
// 3D array of pointers to objects in each cell
|
||||
CullableClass ** Cells;
|
||||
|
||||
// list of objs that were outside or too big for the grid.
|
||||
CullableClass * NoGridList;
|
||||
|
||||
// number of objects in the system
|
||||
int ObjCount;
|
||||
|
||||
// statistics
|
||||
StatsStruct Stats;
|
||||
|
||||
// Structure used to define a volume in the grid. The volume spans from the cell indexed
|
||||
// by Min[0],Min[1],Min[2] to the cell indexed by Max[0]-1,Max[1]-1,Max[2]-1.
|
||||
struct VolumeStruct
|
||||
{
|
||||
VolumeStruct(void);
|
||||
VolumeStruct(int i0,int j0,int k0,int i1,int j1,int k1);
|
||||
bool Is_Leaf(void) const;
|
||||
bool Is_Empty(void) const;
|
||||
void Split(VolumeStruct & v0,VolumeStruct & v1) const;
|
||||
|
||||
int Min[3];
|
||||
int Max[3];
|
||||
};
|
||||
|
||||
void link_object(CullableClass * obj);
|
||||
void link_object(CullableClass * obj,int address);
|
||||
void unlink_object(CullableClass * obj);
|
||||
void link_object_to_list(CullableClass ** head,CullableClass * obj);
|
||||
void unlink_object_from_list(CullableClass ** head,CullableClass * obj);
|
||||
|
||||
bool map_point_to_cell(const Vector3 & pt,int & set_i,int & set_j,int & set_k);
|
||||
bool map_point_to_address(const Vector3 & pt,int & set_address);
|
||||
WWINLINE int map_indices_to_address(int i,int j,int k);
|
||||
void clamp_indices_to_grid(int * i,int * j,int * k);
|
||||
|
||||
int total_cell_count(void);
|
||||
void compute_box(int i,int j,int k,AABoxClass * set_box);
|
||||
void compute_box(const VolumeStruct & area, AABoxClass * set_box);
|
||||
|
||||
void init_volume(const Vector3 & bound_min,const Vector3 & bound_max,VolumeStruct * set_volume);
|
||||
void init_volume(const Vector3 & point,VolumeStruct * set_volume);
|
||||
void init_volume(const LineSegClass & line,VolumeStruct * set_volume);
|
||||
void init_volume(const AABoxClass & box,VolumeStruct * set_volume);
|
||||
void init_volume(const OBBoxClass & box,VolumeStruct * set_volume);
|
||||
void init_volume(const FrustumClass & frustum,VolumeStruct * set_volume);
|
||||
|
||||
void collect_objects_in_leaf(const Vector3 & point,CullableClass * head);
|
||||
void collect_objects_in_leaf(const AABoxClass & aabox,CullableClass * head);
|
||||
void collect_objects_in_leaf(const OBBoxClass & obbox,CullableClass * head);
|
||||
void collect_objects_in_leaf(const FrustumClass & frustum,CullableClass * head);
|
||||
};
|
||||
|
||||
/*
|
||||
** Macros for gathering statistics. Placed here in the header file so that
|
||||
** derived classes can use them as well.
|
||||
*/
|
||||
#ifdef WWDEBUG
|
||||
|
||||
#define GRIDCULL_NODE_ACCEPTED Stats.NodesAccepted ++;
|
||||
#define GRIDCULL_NODE_TRIVIALLY_ACCEPTED Stats.NodesTriviallyAccepted ++;
|
||||
#define GRIDCULL_NODE_REJECTED Stats.NodesRejected ++;
|
||||
|
||||
#else
|
||||
|
||||
#define GRIDCULL_NODE_ACCEPTED
|
||||
#define GRIDCULL_NODE_TRIVIALLY_ACCEPTED
|
||||
#define GRIDCULL_NODE_REJECTED
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** TypedGridCullSystemClass
|
||||
** This class simply enforces that a certain type of object is inserted into the grid cull system.
|
||||
** It exposes the add, remove, and collection iterating functions and is intended to be the class
|
||||
** actually used by the end user.
|
||||
*/
|
||||
template <class T> class TypedGridCullSystemClass : public GridCullSystemClass
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void Add_Object(T * obj) { Add_Object_Internal(obj); }
|
||||
virtual void Remove_Object(T * obj) { Remove_Object_Internal(obj); }
|
||||
|
||||
T * Get_First_Collected_Object(void) { return (T*)Get_First_Collected_Object_Internal(); }
|
||||
T * Get_Next_Collected_Object(T * obj) { return (T*)Get_Next_Collected_Object_Internal(obj); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** GridLinkClass
|
||||
** This structure is used to link cullable objects into a Grid culling system
|
||||
** This class is should only be used by classes which derive from GridCullSystemClass
|
||||
** not normal users.
|
||||
*/
|
||||
class GridLinkClass : public CullLinkClass, public AutoPoolClass<GridLinkClass,256>
|
||||
{
|
||||
public:
|
||||
GridLinkClass(GridCullSystemClass * system);
|
||||
virtual ~GridLinkClass(void);
|
||||
|
||||
int GridAddress; // address in the grid.
|
||||
CullableClass * Prev; // prev object in this cell
|
||||
CullableClass * Next; // next object in this cell
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** GridListIterator
|
||||
** This is just a simple iterator that contains the code for traversing the
|
||||
** list of objects either in a cell in the grid or in the NoGridList...
|
||||
** This class should only be used by classes which derive from GridCullSystemClass
|
||||
** not normal users.
|
||||
*/
|
||||
class GridListIterator
|
||||
{
|
||||
public:
|
||||
|
||||
GridListIterator(CullableClass * head) { First(head); }
|
||||
|
||||
void First(CullableClass * head) { Head = head; CurObj = head; }
|
||||
void First(void) { CurObj = Head; }
|
||||
void Next(void) { if (CurObj) { CurObj = ((GridLinkClass *)CurObj->Get_Cull_Link())->Next; } }
|
||||
void Prev(void) { if (CurObj) { CurObj = ((GridLinkClass *)CurObj->Get_Cull_Link())->Prev; } }
|
||||
bool Is_Done(void) { return (CurObj == NULL); }
|
||||
|
||||
CullableClass * Get_Obj(void) { if (CurObj) { CurObj->Add_Ref(); } return CurObj; }
|
||||
CullableClass * Peek_Obj(void) { return CurObj; }
|
||||
|
||||
private:
|
||||
|
||||
CullableClass * Head; // head of the list we're working in
|
||||
CullableClass * CurObj; // node we're currently at.
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::clamp_indices_to_grid -- constrains indices to be a valid location *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void GridCullSystemClass::clamp_indices_to_grid(int * i,int * j,int * k)
|
||||
{
|
||||
if (*i < 0) *i = 0;
|
||||
if (*i >= CellCount[0]) *i = CellCount[0] - 1;
|
||||
if (*j < 0) *j = 0;
|
||||
if (*j >= CellCount[1]) *j = CellCount[1] - 1;
|
||||
if (*k < 0) *k = 0;
|
||||
if (*k >= CellCount[2]) *k = CellCount[2] - 1;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::map_point_to_cell -- determines which cell the point is in *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE bool GridCullSystemClass::map_point_to_cell(const Vector3 & pt,int & set_i,int & set_j,int & set_k)
|
||||
{
|
||||
Vector3 dp = pt - Origin;
|
||||
set_i = floor(dp.X * OOCellDim.X);
|
||||
set_j = floor(dp.Y * OOCellDim.Y);
|
||||
set_k = floor(dp.Z * OOCellDim.Z);
|
||||
|
||||
if ( (set_i >= 0) && (set_j >= 0) && (set_k >= 0) &&
|
||||
(set_i < CellCount[0]) && (set_j < CellCount[1]) && (set_k < CellCount[2]) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::map_point_to_address -- determines the address of a point in the grid *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE bool GridCullSystemClass::map_point_to_address(const Vector3 & pt,int &set_address)
|
||||
{
|
||||
int i,j,k;
|
||||
bool res = map_point_to_cell(pt,i,j,k);
|
||||
|
||||
if (res) {
|
||||
set_address = map_indices_to_address(i,j,k);
|
||||
return true;
|
||||
} else {
|
||||
set_address = UNGRIDDED_ADDRESS;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::map_indices_to_address -- computes the address for given index triplet *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE int GridCullSystemClass::map_indices_to_address(int i,int j,int k)
|
||||
{
|
||||
return i + j*CellCount[0] + k*CellCount[0]*CellCount[1];
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::total_cell_count -- returns the total number of cells in the grid *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE int GridCullSystemClass::total_cell_count(void)
|
||||
{
|
||||
return CellCount[0] * CellCount[1] * CellCount[2];
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::compute_box -- computes the bounding box for a grid cell *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void GridCullSystemClass::compute_box(int i,int j,int k,AABoxClass * set_box)
|
||||
{
|
||||
WWASSERT(set_box != NULL);
|
||||
WWASSERT((i >= 0) && (j >= 0) && (k >= 0));
|
||||
WWASSERT((i < CellCount[0]) && (j < CellCount[1]) && (k < CellCount[2]));
|
||||
|
||||
Vector3 min,max;
|
||||
|
||||
min.X = Origin.X + i * CellDim.X - MaxObjExtent;
|
||||
min.Y = Origin.Y + j * CellDim.Y - MaxObjExtent;
|
||||
min.Z = Origin.Z + k * CellDim.Z - MaxObjExtent;
|
||||
|
||||
max.X = min.X + CellDim.X + 2.0f*MaxObjExtent;
|
||||
max.Y = min.Y + CellDim.Y + 2.0f*MaxObjExtent;
|
||||
max.Z = min.Z + CellDim.Z + 2.0f*MaxObjExtent;
|
||||
|
||||
set_box->Init((min+max)*0.5f, (min-max)*0.5f);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::compute_box -- computes bounding box for a range of grid cells *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void GridCullSystemClass::compute_box(const GridCullSystemClass::VolumeStruct & vol, AABoxClass * set_box)
|
||||
{
|
||||
WWASSERT(set_box != NULL);
|
||||
WWASSERT((vol.Min[0] >= 0) && (vol.Min[1] >= 0) && (vol.Min[2] >= 0));
|
||||
WWASSERT((vol.Max[0] <= CellCount[0]) && (vol.Max[1] <= CellCount[1]) && (vol.Max[2] <= CellCount[2]));
|
||||
|
||||
Vector3 min,max;
|
||||
|
||||
min.X = Origin.X + vol.Min[0] * CellDim.X - MaxObjExtent;
|
||||
min.Y = Origin.Y + vol.Min[1] * CellDim.Y - MaxObjExtent;
|
||||
min.Z = Origin.Z + vol.Min[2] * CellDim.Z - MaxObjExtent;
|
||||
|
||||
max.X = Origin.X + vol.Max[0] * CellDim.X + MaxObjExtent;
|
||||
max.Y = Origin.Y + vol.Max[1] * CellDim.Y + MaxObjExtent;
|
||||
max.Z = Origin.Z + vol.Max[2] * CellDim.Z + MaxObjExtent;
|
||||
|
||||
Vector3 center((max.X+min.X)*0.5f,(max.Y+min.Y)*0.5f,(max.Z+min.Z)*0.5f);
|
||||
Vector3 extent((max.X-min.X)*0.5f,(max.Y-min.Y)*0.5f,(max.Z-min.Z)*0.5f);
|
||||
set_box->Init(center,extent);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given range *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void GridCullSystemClass::init_volume
|
||||
(
|
||||
const Vector3 & bound_min,
|
||||
const Vector3 & bound_max,
|
||||
VolumeStruct * set_vol
|
||||
)
|
||||
{
|
||||
// expand the box by the maximum size of any object
|
||||
Vector3 grid_min = bound_min;
|
||||
grid_min.X -= MaxObjExtent;
|
||||
grid_min.Y -= MaxObjExtent;
|
||||
grid_min.Z -= MaxObjExtent;
|
||||
|
||||
Vector3 grid_max = bound_max;
|
||||
grid_max.X += MaxObjExtent;
|
||||
grid_max.Y += MaxObjExtent;
|
||||
grid_max.Z += MaxObjExtent;
|
||||
|
||||
// now compute the grid coordinates of the corners of the box
|
||||
GridCullSystemClass::map_point_to_cell(grid_min,set_vol->Min[0],set_vol->Min[1],set_vol->Min[2]);
|
||||
GridCullSystemClass::map_point_to_cell(grid_max,set_vol->Max[0],set_vol->Max[1],set_vol->Max[2]);
|
||||
|
||||
// now clamp the volume to the actual grid
|
||||
clamp_indices_to_grid(&(set_vol->Min[0]),&(set_vol->Min[1]),&(set_vol->Min[2]));
|
||||
clamp_indices_to_grid(&(set_vol->Max[0]),&(set_vol->Max[1]),&(set_vol->Max[2]));
|
||||
|
||||
// increment the outer edge of the box due to the way we traverse the grid...
|
||||
set_vol->Max[0] ++;
|
||||
set_vol->Max[1] ++;
|
||||
set_vol->Max[2] ++;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given line segment *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void GridCullSystemClass::init_volume(const LineSegClass & line,VolumeStruct * set_volume)
|
||||
{
|
||||
Vector3 min_pt,max_pt;
|
||||
min_pt.X = WWMath::Min(line.Get_P0().X,line.Get_P1().X);
|
||||
max_pt.X = WWMath::Max(line.Get_P0().X,line.Get_P1().X);
|
||||
min_pt.Y = WWMath::Min(line.Get_P0().Y,line.Get_P1().Y);
|
||||
max_pt.Y = WWMath::Max(line.Get_P0().Y,line.Get_P1().Y);
|
||||
min_pt.Z = WWMath::Min(line.Get_P0().Z,line.Get_P1().Z);
|
||||
max_pt.Z = WWMath::Max(line.Get_P0().Z,line.Get_P1().Z);
|
||||
init_volume(min_pt,max_pt,set_volume);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given box *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void GridCullSystemClass::init_volume(const AABoxClass & box,VolumeStruct * set_volume)
|
||||
{
|
||||
init_volume(box.Center - box.Extent,box.Center + box.Extent,set_volume);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given oriented box *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void GridCullSystemClass::init_volume(const OBBoxClass & box,VolumeStruct * set_volume)
|
||||
{
|
||||
Vector3 aaextent;
|
||||
box.Compute_Axis_Aligned_Extent(&aaextent);
|
||||
init_volume(box.Center - aaextent,box.Center + aaextent,set_volume);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::init_volume -- inits volume to contain the given frustum *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void GridCullSystemClass::init_volume(const FrustumClass & frustum,VolumeStruct * set_volume)
|
||||
{
|
||||
init_volume(frustum.Get_Bound_Min(),frustum.Get_Bound_Max(),set_volume);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::VolumeStruct::VolumeStruct -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*=============================================================================================*/
|
||||
WWINLINE GridCullSystemClass::VolumeStruct::VolumeStruct(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::VolumeStruct::VolumeStruct -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE GridCullSystemClass::VolumeStruct::VolumeStruct(int i0,int j0,int k0,int i1,int j1,int k1)
|
||||
{
|
||||
Min[0] = i0;
|
||||
Min[1] = j0;
|
||||
Min[2] = k0;
|
||||
Max[0] = i1;
|
||||
Max[1] = j1;
|
||||
Max[2] = k1;
|
||||
WWASSERT(Max[0] > Min[0]);
|
||||
WWASSERT(Max[1] > Min[1]);
|
||||
WWASSERT(Max[2] > Min[2]);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::VolumeStruct::Is_Leaf -- check if volume is a leaf *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE bool GridCullSystemClass::VolumeStruct::Is_Leaf(void) const
|
||||
{
|
||||
return ((Max[0]-Min[0] == 1) && (Max[1]-Min[1] == 1) && (Max[2]-Min[2] == 1));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::VolumeStruct::Is_Empty -- check if volume is empty (or invalid) *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE bool GridCullSystemClass::VolumeStruct::Is_Empty(void) const
|
||||
{
|
||||
return ((Max[0]-Min[0] <= 0) || (Max[1]-Min[1] <= 0) || (Max[2]-Min[2] <= 0));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* GridCullSystemClass::VolumeStruct::Split -- split this volume *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/30/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void GridCullSystemClass::VolumeStruct::Split(VolumeStruct & v0,VolumeStruct & v1) const
|
||||
{
|
||||
// find the longest dimension
|
||||
int split_axis = 0;
|
||||
int delta[3];
|
||||
|
||||
delta[0] = Max[0] - Min[0];
|
||||
delta[1] = Max[1] - Min[1];
|
||||
delta[2] = Max[2] - Min[2];
|
||||
|
||||
if (delta[1] > delta[split_axis]) split_axis = 1;
|
||||
if (delta[2] > delta[split_axis]) split_axis = 2;
|
||||
|
||||
WWASSERT(delta[split_axis] > 0);
|
||||
|
||||
// split the volume perpendicularly to that dimension
|
||||
memcpy(&v0,this,sizeof(VolumeStruct));
|
||||
memcpy(&v1,this,sizeof(VolumeStruct));
|
||||
|
||||
v0.Max[split_axis] = v1.Min[split_axis] = Min[split_axis] + (delta[split_axis] >> 1);
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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:: /VSS_Sync/wwmath/hermitespline.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 6/13/01 2:18p $*
|
||||
* *
|
||||
* $Revision:: 11 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "hermitespline.h"
|
||||
#include "wwmathids.h"
|
||||
#include "persistfactory.h"
|
||||
#include "wwhack.h"
|
||||
|
||||
|
||||
/*
|
||||
** Force-Link this module because the linker can't detect that we actually need it...
|
||||
*/
|
||||
DECLARE_FORCE_LINK(hermitespline);
|
||||
|
||||
/*
|
||||
** Save-Load stuff
|
||||
*/
|
||||
SimplePersistFactoryClass<HermiteSpline3DClass,WWMATH_CHUNKID_HERMITESPLINE3D> _HermiteSpline3DFactory;
|
||||
SimplePersistFactoryClass<HermiteSpline1DClass,WWMATH_CHUNKID_HERMITESPLINE1D> _HermiteSpline1DFactory;
|
||||
|
||||
enum
|
||||
{
|
||||
// ID's used by HermiteSpline3D
|
||||
HERMITE3D_CHUNK_CURVE3D = 0x00020727,
|
||||
HERMITE3D_CHUNK_TANGENTS,
|
||||
|
||||
// ID's used by HermiteSpline1D
|
||||
HERMITE1D_CHUNK_CURVE1D = 0x00020729,
|
||||
HERMITE1D_CHUNK_TANGENTS,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Hermite Spline
|
||||
*/
|
||||
const HermiteSpline3DClass &HermiteSpline3DClass::operator= (const HermiteSpline3DClass &that)
|
||||
{
|
||||
//
|
||||
// This is included for completeness only, it basically
|
||||
// implements the default bitwise copy operator.
|
||||
//
|
||||
TangentsDirty = that.TangentsDirty;
|
||||
Tangents = that.Tangents;
|
||||
Curve3DClass::operator= (that);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
void HermiteSpline3DClass::Set_Looping(bool onoff)
|
||||
{
|
||||
if (onoff != IsLooping) {
|
||||
Curve3DClass::Set_Looping(onoff);
|
||||
TangentsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void HermiteSpline3DClass::Evaluate(float time,Vector3 * set_val)
|
||||
{
|
||||
// if we're outside the range, return the start or end...
|
||||
if (time < Keys[0].Time) {
|
||||
*set_val = Keys[0].Point;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time > Keys[Keys.Count() - 1].Time) {
|
||||
*set_val = Keys[Keys.Count() - 1].Point;
|
||||
return;
|
||||
}
|
||||
|
||||
// if the tangents are marked dirty, give derived classes a chance to recompute them
|
||||
if (TangentsDirty) {
|
||||
Update_Tangents();
|
||||
}
|
||||
|
||||
// ok find the segment
|
||||
int i0,i1;
|
||||
float t;
|
||||
Find_Interval(time,&i0,&i1,&t);
|
||||
|
||||
float t2 = t*t;
|
||||
float t3 = t2*t;
|
||||
|
||||
// hermite basis functions:
|
||||
float h0 = 2*t3 - 3*t2 + 1;
|
||||
float h1 = -2*t3 + 3*t2;
|
||||
float h2 = t3 - 2*t2 + t;
|
||||
float h3 = t3 - t2;
|
||||
|
||||
set_val->X = h0*Keys[i0].Point.X + h1*Keys[i1].Point.X +
|
||||
h2*Tangents[i0].OutTangent.X + h3*Tangents[i1].InTangent.X;
|
||||
|
||||
set_val->Y = h0*Keys[i0].Point.Y + h1*Keys[i1].Point.Y +
|
||||
h2*Tangents[i0].OutTangent.Y + h3*Tangents[i1].InTangent.Y;
|
||||
|
||||
set_val->Z = h0*Keys[i0].Point.Z + h1*Keys[i1].Point.Z +
|
||||
h2*Tangents[i0].OutTangent.Z + h3*Tangents[i1].InTangent.Z;
|
||||
}
|
||||
|
||||
void HermiteSpline3DClass::Evaluate_Derivative(float time,Vector3 * set_val)
|
||||
{
|
||||
// if we're outside the range, return the value for the start or end...
|
||||
float min_time = Keys[0].Time;
|
||||
float max_time = Keys[Keys.Count() - 1].Time;
|
||||
time = MAX(time, min_time);
|
||||
time = MIN(time, max_time);
|
||||
|
||||
// if the tangents are marked dirty, give derived classes a chance to recompute them
|
||||
if (TangentsDirty) {
|
||||
Update_Tangents();
|
||||
}
|
||||
|
||||
// ok find the segment
|
||||
int i0,i1;
|
||||
float t;
|
||||
Find_Interval(time,&i0,&i1,&t);
|
||||
|
||||
float t2 = t*t;
|
||||
|
||||
// derivatives of hermite basis functions:
|
||||
float dh0 = 6*t2 - 6*t;
|
||||
float dh1 = -6*t2 + 6*t;
|
||||
float dh2 = 3*t2 - 4*t + 1;
|
||||
float dh3 = 3*t2 - 2*t;
|
||||
|
||||
set_val->X = dh0*Keys[i0].Point.X + dh1*Keys[i1].Point.X +
|
||||
dh2*Tangents[i0].OutTangent.X + dh3*Tangents[i1].InTangent.X;
|
||||
|
||||
set_val->Y = dh0*Keys[i0].Point.Y + dh1*Keys[i1].Point.Y +
|
||||
dh2*Tangents[i0].OutTangent.Y + dh3*Tangents[i1].InTangent.Y;
|
||||
|
||||
set_val->Z = dh0*Keys[i0].Point.Z + dh1*Keys[i1].Point.Z +
|
||||
dh2*Tangents[i0].OutTangent.Z + dh3*Tangents[i1].InTangent.Z;
|
||||
}
|
||||
|
||||
void HermiteSpline3DClass::Set_Key(int i,const Vector3 & point)
|
||||
{
|
||||
Curve3DClass::Set_Key(i,point);
|
||||
TangentsDirty = true;
|
||||
}
|
||||
|
||||
int HermiteSpline3DClass::Add_Key(const Vector3 & point,float t)
|
||||
{
|
||||
int index = Curve3DClass::Add_Key(point,t);
|
||||
TangentsDirty = true;
|
||||
TangentsClass tan;
|
||||
tan.InTangent.Set(0,0,0);
|
||||
tan.OutTangent.Set(0,0,0);
|
||||
Tangents.Insert(index,tan);
|
||||
return index;
|
||||
}
|
||||
|
||||
void HermiteSpline3DClass::Remove_Key(int i)
|
||||
{
|
||||
Tangents.Delete(i);
|
||||
Curve3DClass::Remove_Key(i);
|
||||
TangentsDirty = true;
|
||||
}
|
||||
|
||||
void HermiteSpline3DClass::Clear_Keys(void)
|
||||
{
|
||||
Tangents.Clear();
|
||||
Curve3DClass::Clear_Keys();
|
||||
TangentsDirty = true;
|
||||
}
|
||||
|
||||
void HermiteSpline3DClass::Set_Tangents(int i,const Vector3 & in_tan,const Vector3 & out_tan)
|
||||
{
|
||||
assert(i>=0);
|
||||
assert(i<Keys.Count());
|
||||
Tangents[i].InTangent = in_tan;
|
||||
Tangents[i].OutTangent = out_tan;
|
||||
}
|
||||
|
||||
void HermiteSpline3DClass::Get_Tangents(int i,Vector3 * set_in,Vector3 * set_out)
|
||||
{
|
||||
assert(i>=0);
|
||||
assert(i<Keys.Count());
|
||||
*set_in = Tangents[i].InTangent;
|
||||
*set_out = Tangents[i].OutTangent;
|
||||
}
|
||||
|
||||
const PersistFactoryClass & HermiteSpline3DClass::Get_Factory(void) const
|
||||
{
|
||||
return _HermiteSpline3DFactory;
|
||||
}
|
||||
|
||||
bool HermiteSpline3DClass::Save(ChunkSaveClass &csave)
|
||||
{
|
||||
csave.Begin_Chunk(HERMITE3D_CHUNK_CURVE3D);
|
||||
Curve3DClass::Save(csave);
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.Begin_Chunk(HERMITE3D_CHUNK_TANGENTS);
|
||||
for (int i=0; i<Tangents.Count(); i++) {
|
||||
csave.Write(&(Tangents[i].InTangent),sizeof(Tangents[i].InTangent));
|
||||
csave.Write(&(Tangents[i].OutTangent),sizeof(Tangents[i].OutTangent));
|
||||
}
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HermiteSpline3DClass::Load(ChunkLoadClass &cload)
|
||||
{
|
||||
int i;
|
||||
TangentsClass newtangent;
|
||||
|
||||
// reset the array of tangents
|
||||
Tangents.Delete_All();
|
||||
|
||||
// read in the chunks
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case HERMITE3D_CHUNK_CURVE3D:
|
||||
Curve3DClass::Load(cload);
|
||||
break;
|
||||
|
||||
case HERMITE3D_CHUNK_TANGENTS:
|
||||
for (i=0; i<Keys.Count(); i++) {
|
||||
cload.Read(&(newtangent.InTangent),sizeof(newtangent.InTangent));
|
||||
cload.Read(&(newtangent.OutTangent),sizeof(newtangent.OutTangent));
|
||||
Tangents.Add(newtangent);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
WWASSERT(Keys.Count() == Tangents.Count());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** 1-Dimensional Hermite Spline
|
||||
*/
|
||||
void HermiteSpline1DClass::Set_Looping(bool onoff)
|
||||
{
|
||||
if (onoff != IsLooping) {
|
||||
Curve1DClass::Set_Looping(onoff);
|
||||
TangentsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void HermiteSpline1DClass::Evaluate(float time,float * set_val)
|
||||
{
|
||||
if (Keys.Count() == 1)
|
||||
{
|
||||
*set_val = Keys[0].Point;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsLooping)
|
||||
{
|
||||
// if we're outside the range, return the start or end...
|
||||
if (time < Keys[0].Time) {
|
||||
*set_val = Keys[0].Point;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time > Keys[Keys.Count() - 1].Time) {
|
||||
*set_val = Keys[Keys.Count() - 1].Point;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if the tangents are marked dirty, give derived classes a chance to recompute them
|
||||
if (TangentsDirty) {
|
||||
Update_Tangents();
|
||||
}
|
||||
|
||||
// ok find the segment
|
||||
int i0,i1;
|
||||
float t;
|
||||
Find_Interval(time,&i0,&i1,&t);
|
||||
|
||||
float t2 = t*t;
|
||||
float t3 = t2*t;
|
||||
|
||||
// hermite basis functions:
|
||||
float h0 = 2*t3 - 3*t2 + 1;
|
||||
float h1 = -2*t3 + 3*t2;
|
||||
float h2 = t3 - 2*t2 + t;
|
||||
float h3 = t3 - t2;
|
||||
|
||||
*set_val = h0*Keys[i0].Point + h1*Keys[i1].Point +
|
||||
h2*Tangents[i0].OutTangent + h3*Tangents[i1].InTangent;
|
||||
}
|
||||
|
||||
void HermiteSpline1DClass::Set_Key(int i,float point,unsigned int extra)
|
||||
{
|
||||
Curve1DClass::Set_Key(i,point,extra);
|
||||
TangentsDirty = true;
|
||||
}
|
||||
|
||||
int HermiteSpline1DClass::Add_Key(float point,float t,unsigned int extra)
|
||||
{
|
||||
int index = Curve1DClass::Add_Key(point,t,extra);
|
||||
TangentsDirty = true;
|
||||
TangentsClass tan;
|
||||
tan.InTangent = 0.0f;
|
||||
tan.OutTangent = 0.0f;
|
||||
Tangents.Insert(index,tan);
|
||||
return index;
|
||||
}
|
||||
|
||||
void HermiteSpline1DClass::Remove_Key(int i)
|
||||
{
|
||||
Tangents.Delete(i);
|
||||
Curve1DClass::Remove_Key(i);
|
||||
TangentsDirty = true;
|
||||
}
|
||||
|
||||
void HermiteSpline1DClass::Clear_Keys(void)
|
||||
{
|
||||
Tangents.Clear();
|
||||
Curve1DClass::Clear_Keys();
|
||||
TangentsDirty = true;
|
||||
}
|
||||
|
||||
void HermiteSpline1DClass::Set_Tangents(int i,float in_tan,float out_tan)
|
||||
{
|
||||
assert(i>=0);
|
||||
assert(i<Keys.Count());
|
||||
Tangents[i].InTangent = in_tan;
|
||||
Tangents[i].OutTangent = out_tan;
|
||||
}
|
||||
|
||||
void HermiteSpline1DClass::Get_Tangents(int i,float * set_in,float * set_out)
|
||||
{
|
||||
assert(i>=0);
|
||||
assert(i<Keys.Count());
|
||||
*set_in = Tangents[i].InTangent;
|
||||
*set_out = Tangents[i].OutTangent;
|
||||
}
|
||||
|
||||
const PersistFactoryClass & HermiteSpline1DClass::Get_Factory(void) const
|
||||
{
|
||||
return _HermiteSpline1DFactory;
|
||||
}
|
||||
|
||||
bool HermiteSpline1DClass::Save(ChunkSaveClass &csave)
|
||||
{
|
||||
if (TangentsDirty) {
|
||||
Update_Tangents();
|
||||
}
|
||||
|
||||
csave.Begin_Chunk(HERMITE1D_CHUNK_CURVE1D);
|
||||
Curve1DClass::Save(csave);
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.Begin_Chunk(HERMITE1D_CHUNK_TANGENTS);
|
||||
for (int i=0; i<Tangents.Count(); i++) {
|
||||
csave.Write(&(Tangents[i].InTangent),sizeof(Tangents[i].InTangent));
|
||||
csave.Write(&(Tangents[i].OutTangent),sizeof(Tangents[i].OutTangent));
|
||||
}
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HermiteSpline1DClass::Load(ChunkLoadClass &cload)
|
||||
{
|
||||
int i;
|
||||
TangentsClass newtangent;
|
||||
|
||||
// reset the tangents array
|
||||
Tangents.Delete_All();
|
||||
|
||||
// read in the chunks
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case HERMITE1D_CHUNK_CURVE1D:
|
||||
Curve1DClass::Load(cload);
|
||||
break;
|
||||
|
||||
case HERMITE1D_CHUNK_TANGENTS:
|
||||
for (i=0; i<Keys.Count(); i++) {
|
||||
cload.Read(&(newtangent.InTangent),sizeof(newtangent.InTangent));
|
||||
cload.Read(&(newtangent.OutTangent),sizeof(newtangent.OutTangent));
|
||||
Tangents.Add(newtangent);
|
||||
}
|
||||
TangentsDirty = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
WWASSERT(Keys.Count() == Tangents.Count());
|
||||
return true;
|
||||
}
|
||||
|
||||
143
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/hermitespline.h
Normal file
143
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/hermitespline.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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:: /VSS_Sync/wwmath/hermitespline.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 6/13/01 2:18p $*
|
||||
* *
|
||||
* $Revision:: 7 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef HERMITE_H
|
||||
#define HERMITE_H
|
||||
|
||||
#include "curve.h"
|
||||
|
||||
/*
|
||||
** HermiteSpline3DClass
|
||||
** 3-Dimensional hermite spline interpolation
|
||||
** Hermite splines require you to input all of the tangents...
|
||||
*/
|
||||
class HermiteSpline3DClass : public Curve3DClass
|
||||
{
|
||||
public:
|
||||
HermiteSpline3DClass(void)
|
||||
: TangentsDirty (true) { }
|
||||
|
||||
HermiteSpline3DClass(const HermiteSpline3DClass &that)
|
||||
: TangentsDirty (true) { (*this) = that; }
|
||||
|
||||
const HermiteSpline3DClass &operator= (const HermiteSpline3DClass &that);
|
||||
|
||||
virtual void Evaluate(float time,Vector3 * set_val);
|
||||
virtual void Evaluate_Derivative(float time,Vector3 * set_val);
|
||||
virtual void Set_Looping(bool onoff);
|
||||
|
||||
virtual void Set_Key(int i,const Vector3 & point);
|
||||
virtual int Add_Key(const Vector3 & point,float t);
|
||||
virtual void Remove_Key(int i);
|
||||
virtual void Clear_Keys(void);
|
||||
|
||||
virtual void Set_Tangents(int i,const Vector3 & in_tan,const Vector3 & out_tan);
|
||||
virtual void Get_Tangents(int i,Vector3 * set_in,Vector3 * set_out);
|
||||
|
||||
virtual void Update_Tangents(void) { TangentsDirty = false; }
|
||||
|
||||
// save-load support
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
|
||||
protected:
|
||||
|
||||
class TangentsClass
|
||||
{
|
||||
public:
|
||||
Vector3 InTangent;
|
||||
Vector3 OutTangent;
|
||||
bool operator == (const TangentsClass & that) { return ((InTangent == that.InTangent) && (OutTangent == that.OutTangent)); }
|
||||
bool operator != (const TangentsClass & that) { return !TangentsClass::operator == (that); }
|
||||
};
|
||||
|
||||
bool TangentsDirty;
|
||||
DynamicVectorClass<TangentsClass> Tangents;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** HermiteSpline1DClass
|
||||
** 1-Dimensional hermite spline interpolation
|
||||
** Hermite splines require you to input all of the tangents...
|
||||
*/
|
||||
class HermiteSpline1DClass : public Curve1DClass
|
||||
{
|
||||
public:
|
||||
HermiteSpline1DClass (void)
|
||||
: TangentsDirty (true) { }
|
||||
|
||||
virtual void Evaluate(float time,float * set_val);
|
||||
virtual void Set_Looping(bool onoff);
|
||||
|
||||
virtual void Set_Key(int i,float point,unsigned int extra=0);
|
||||
virtual int Add_Key(float point,float t,unsigned int extra=0);
|
||||
virtual void Remove_Key(int i);
|
||||
virtual void Clear_Keys(void);
|
||||
|
||||
virtual void Set_Tangents(int i,float in_tan,float out_tan);
|
||||
virtual void Get_Tangents(int i,float * set_in,float * set_out);
|
||||
|
||||
// save-load support
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
|
||||
protected:
|
||||
|
||||
class TangentsClass
|
||||
{
|
||||
public:
|
||||
float InTangent;
|
||||
float OutTangent;
|
||||
bool operator == (const TangentsClass & that) { return ((InTangent == that.InTangent) && (OutTangent == that.OutTangent)); }
|
||||
bool operator != (const TangentsClass & that) { return !TangentsClass::operator == (that); }
|
||||
};
|
||||
|
||||
virtual void Update_Tangents(void) { TangentsDirty = false; }
|
||||
|
||||
bool TangentsDirty;
|
||||
DynamicVectorClass<TangentsClass> Tangents;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
231
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/lineseg.cpp
Normal file
231
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/lineseg.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/lineseg.cpp $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 3/16/00 3:16p $*
|
||||
* *
|
||||
* $Revision:: 25 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* LineSegClass::Set -- Initialize this 'lineseg' by transforming another 'lineseg' *
|
||||
* LineSegClass::Set_Random -- create a random linesegment within the given space *
|
||||
* LineSegClass::Find_Point_Closest_To -- Finds point on line closest to point supplied. *
|
||||
* LineSegClass::Find_Intersection -- Finds the closest points on the two lines *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "lineseg.h"
|
||||
//#include <stdlib.h>
|
||||
|
||||
#include "matrix3d.h"
|
||||
|
||||
/***********************************************************************************************
|
||||
* LineSegClass::Set -- Initialize this 'lineseg' by transforming another 'lineseg' *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/17/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void LineSegClass::Set(const LineSegClass & that,const Matrix3D & tm)
|
||||
{
|
||||
/*
|
||||
** Transform P0 and P1
|
||||
*/
|
||||
Matrix3D::Transform_Vector(tm,that.P0,&P0);
|
||||
Matrix3D::Transform_Vector(tm,that.P1,&P1);
|
||||
|
||||
/*
|
||||
** Just calculate DP
|
||||
*/
|
||||
DP = P1 - P0;
|
||||
|
||||
/*
|
||||
** Rotate the direction vector
|
||||
*/
|
||||
Matrix3D::Rotate_Vector(tm,that.Dir,&Dir);
|
||||
|
||||
/*
|
||||
** Length should be un-changed
|
||||
*/
|
||||
Length = that.Length;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* LineSegClass::Set_Random -- create a random linesegment within the given space *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void LineSegClass::Set_Random(const Vector3 & min,const Vector3 & max)
|
||||
{
|
||||
float frac;
|
||||
|
||||
frac = WWMath::Random_Float();
|
||||
P0.X = min.X + frac * (max.X - min.X);
|
||||
frac = WWMath::Random_Float();
|
||||
P0.Y = min.Y + frac * (max.Y - min.Y);
|
||||
frac = WWMath::Random_Float();
|
||||
P0.Z = min.Z + frac * (max.Z - min.Z);
|
||||
|
||||
frac = WWMath::Random_Float();
|
||||
P1.X = min.X + frac * (max.X - min.X);
|
||||
frac = WWMath::Random_Float();
|
||||
P1.Y = min.Y + frac * (max.Y - min.Y);
|
||||
frac = WWMath::Random_Float();
|
||||
P1.Z = min.Z + frac * (max.Z - min.Z);
|
||||
|
||||
DP = P1 - P0;
|
||||
Dir = DP;
|
||||
Dir.Normalize();
|
||||
Length = DP.Length();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* LineSegClass::Find_Point_Closest_To -- Finds point on line closest to point supplied. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 07/26/1999 SKB : Created. *
|
||||
*=============================================================================================*/
|
||||
Vector3 LineSegClass::Find_Point_Closest_To(const Vector3 &pos) const
|
||||
{
|
||||
// Get a vector from one line endpoint to point in question.
|
||||
Vector3 v_0_pos = (pos - P0);
|
||||
float dotprod = Vector3::Dot_Product(Dir, v_0_pos);
|
||||
|
||||
// Check to see if point is past either of the endpoints.
|
||||
// (Unable to draw a perpendicular line from the point to the line segment.)
|
||||
if (dotprod <= 0.0) {
|
||||
return(P0);
|
||||
} else if (dotprod >= Length) {
|
||||
return(P1);
|
||||
}
|
||||
|
||||
// Find point on line seg that is closest to pos passed in.
|
||||
Vector3 point = P0 + (dotprod * Dir);
|
||||
return(point);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* LineSegClass::Find_Intersection -- Finds the closest points on the two lines.. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 03/03/2000 PDS : Created. *
|
||||
*=============================================================================================*/
|
||||
bool
|
||||
LineSegClass::Find_Intersection
|
||||
(
|
||||
const LineSegClass & other_line,
|
||||
Vector3 * p1,
|
||||
float * fraction1,
|
||||
Vector3 * p2,
|
||||
float * fraction2
|
||||
) const
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
Vector3 cross1 = Vector3::Cross_Product (Dir, other_line.Dir);
|
||||
Vector3 cross2 = Vector3::Cross_Product (other_line.P0 - P0, other_line.Dir);
|
||||
float top1 = cross2 * cross1;
|
||||
float bottom1 = cross1 * cross1;
|
||||
|
||||
Vector3 cross3 = Vector3::Cross_Product (other_line.Dir, Dir);
|
||||
Vector3 cross4 = Vector3::Cross_Product (P0 - other_line.P0, Dir);
|
||||
float top2 = cross4 * cross3;
|
||||
float bottom2 = cross3 * cross3;
|
||||
#else
|
||||
Vector3 cross1, cross2, cross3, cross4;
|
||||
|
||||
Vector3::Cross_Product(Dir, other_line.Dir, &cross1);
|
||||
Vector3::Cross_Product(other_line.P0 - P0, other_line.Dir, &cross2);
|
||||
float top1 = Vector3::Dot_Product(cross2, cross1);
|
||||
float bottom1 = Vector3::Dot_Product(cross1, cross1);
|
||||
|
||||
Vector3::Cross_Product(other_line.Dir, Dir, &cross3);
|
||||
Vector3::Cross_Product(P0 - other_line.P0, Dir, &cross4);
|
||||
float top2 = Vector3::Dot_Product(cross4, cross3);
|
||||
float bottom2 = Vector3::Dot_Product(cross3, cross3);
|
||||
#endif
|
||||
|
||||
//
|
||||
// If either of the divisors are 0, then the lines are parallel
|
||||
//
|
||||
if (bottom1 != 0 && bottom2 != 0) {
|
||||
float length1 = top1 / bottom1;
|
||||
float length2 = top2 / bottom2;
|
||||
|
||||
//
|
||||
// Calculate the closest points on both lines.
|
||||
// Note: If the points are the same, then the lines intersect.
|
||||
//
|
||||
(*p1) = P0 + (Dir * length1);
|
||||
(*p2) = other_line.P0 + (other_line.Dir * length2);
|
||||
|
||||
//
|
||||
// Return the fractions if they caller wants them
|
||||
//
|
||||
if (fraction1 != NULL) {
|
||||
(*fraction1) = length1 / Length;
|
||||
}
|
||||
|
||||
if (fraction2 != NULL) {
|
||||
(*fraction2) = length2 / Length;
|
||||
}
|
||||
|
||||
retval = true;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
93
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/lineseg.h
Normal file
93
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/lineseg.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/lineseg.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 3/16/00 3:16p $*
|
||||
* *
|
||||
* $Revision:: 21 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef LINESEG_H
|
||||
#define LINESEG_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector3.h"
|
||||
#include "castres.h"
|
||||
|
||||
class TriClass;
|
||||
class AABoxClass;
|
||||
class OBBoxClass;
|
||||
class PlaneClass;
|
||||
class SphereClass;
|
||||
class Matrix3D;
|
||||
|
||||
|
||||
class LineSegClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
LineSegClass(void) { }
|
||||
LineSegClass(const Vector3 & p0,const Vector3 & p1) : P0(p0), P1(p1) { recalculate(); }
|
||||
LineSegClass(const LineSegClass & that,const Matrix3D & tm) { Set(that,tm); }
|
||||
|
||||
void Set(const Vector3 & p0,const Vector3 & p1) { P0 = p0; P1 = p1; recalculate(); }
|
||||
void Set(const LineSegClass & that,const Matrix3D & tm);
|
||||
void Set_Random(const Vector3 & min,const Vector3 & max);
|
||||
|
||||
const Vector3 & Get_P0() const { return P0; } // start point
|
||||
const Vector3 & Get_P1() const { return P1; } // end point
|
||||
const Vector3 & Get_DP() const { return DP; } // difference of the two points
|
||||
const Vector3 & Get_Dir() const { return Dir; } // normalized direction.
|
||||
float Get_Length() const { return Length; } // length of the segment
|
||||
|
||||
void Compute_Point(float t,Vector3 * set) const { Vector3::Add(P0,t*DP,set); }
|
||||
|
||||
Vector3 Find_Point_Closest_To(const Vector3 &pos) const;
|
||||
bool Find_Intersection (const LineSegClass &other_line, Vector3 *p1, float *fraction1, Vector3 *p2, float *fraction2) const;
|
||||
|
||||
protected:
|
||||
|
||||
void recalculate(void) { DP = P1 - P0; Dir = DP; Dir.Normalize(); Length = DP.Length(); }
|
||||
|
||||
Vector3 P0; // start point
|
||||
Vector3 P1; // end point
|
||||
Vector3 DP; // difference of the two points
|
||||
Vector3 Dir; // normalized direction.
|
||||
float Length; // length of the segment
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
250
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/lookuptable.cpp
Normal file
250
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/lookuptable.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 : WWPhys *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/wwmath/lookuptable.cpp $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Byon_g $*
|
||||
* *
|
||||
* $Modtime:: 7/23/01 6:18p $*
|
||||
* *
|
||||
* $Revision:: 5 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "lookuptable.h"
|
||||
#include "curve.h"
|
||||
#include "wwfile.h"
|
||||
#include "ffactory.h"
|
||||
#include "chunkio.h"
|
||||
#include "persistfactory.h"
|
||||
#include "vector2.h"
|
||||
|
||||
|
||||
/*
|
||||
** Static members
|
||||
*/
|
||||
RefMultiListClass<LookupTableClass> LookupTableMgrClass::Tables;
|
||||
|
||||
/*
|
||||
** Save-Load stuff. Lookup tables are basically saved 1D curve classes. They are turned
|
||||
** into tables at load time. For future expansion, the curve is wrapped in a chunk.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
LOOKUPTABLE_CHUNK_CURVE = 03071200,
|
||||
LOOKUPTABLE_CHUNK_EXTENTS,
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
**
|
||||
** LookupTableClass Implementation
|
||||
**
|
||||
***********************************************************************************************/
|
||||
LookupTableClass::LookupTableClass(int sample_count) :
|
||||
MinInputValue(0.0f),
|
||||
MaxInputValue(0.0f),
|
||||
OutputSamples(sample_count)
|
||||
{
|
||||
}
|
||||
|
||||
LookupTableClass::~LookupTableClass(void)
|
||||
{
|
||||
}
|
||||
|
||||
void LookupTableClass::Init(const char * name,Curve1DClass * curve)
|
||||
{
|
||||
// copy the name
|
||||
Name = name;
|
||||
|
||||
// Store the min and max input values for the table
|
||||
curve->Get_Key(0,NULL,&MinInputValue,NULL);
|
||||
curve->Get_Key(curve->Key_Count()-1,NULL,&MaxInputValue,NULL);
|
||||
OOMaxMinusMin = 1.0f / (MaxInputValue - MinInputValue);
|
||||
|
||||
// Sample the curve and store the output values
|
||||
for (int i=0; i<OutputSamples.Length(); i++) {
|
||||
float x = MinInputValue + (MaxInputValue - MinInputValue) * (float)i / (float)(OutputSamples.Length() - 1);
|
||||
float y;
|
||||
curve->Evaluate(x,&y);
|
||||
OutputSamples[i] = y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
**
|
||||
** LookupTableManager Implementation
|
||||
**
|
||||
***********************************************************************************************/
|
||||
void LookupTableMgrClass::Init(void)
|
||||
{
|
||||
// create a default table that the user can use in an emergency
|
||||
LookupTableClass * default_table = NEW_REF(LookupTableClass,(2));
|
||||
LinearCurve1DClass * default_curve = W3DNEW LinearCurve1DClass;
|
||||
|
||||
default_curve->Add_Key(0.5f,0.0f);
|
||||
default_curve->Add_Key(0.5f,1.0f);
|
||||
default_table->Init("DefaultTable",default_curve);
|
||||
Add_Table(default_table);
|
||||
|
||||
delete default_curve;
|
||||
default_table->Release_Ref();
|
||||
}
|
||||
|
||||
void LookupTableMgrClass::Shutdown(void)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void LookupTableMgrClass::Reset(void)
|
||||
{
|
||||
while (Tables.Peek_Head() != NULL) {
|
||||
Tables.Release_Head();
|
||||
}
|
||||
}
|
||||
|
||||
bool LookupTableMgrClass::Add_Table(LookupTableClass * table)
|
||||
{
|
||||
return Tables.Add(table);
|
||||
}
|
||||
|
||||
bool LookupTableMgrClass::Remove_Table(LookupTableClass * table)
|
||||
{
|
||||
return Tables.Remove(table);
|
||||
}
|
||||
|
||||
LookupTableClass * LookupTableMgrClass::Get_Table(const char * name,bool try_to_load)
|
||||
{
|
||||
// check if we already have this table loaded...
|
||||
RefMultiListIterator<LookupTableClass> it(&Tables);
|
||||
for (it.First(); !it.Is_Done(); it.Next()) {
|
||||
if (stricmp(it.Peek_Obj()->Get_Name(),name) == 0) {
|
||||
return it.Get_Obj(); // add a reference for the user...
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise we can try to load it.
|
||||
LookupTableClass * new_table = NULL;
|
||||
if (try_to_load) {
|
||||
|
||||
FileClass * file = _TheFileFactory->Get_File(name);
|
||||
if (file && file->Open()) {
|
||||
|
||||
ChunkLoadClass cload(file);
|
||||
|
||||
Curve1DClass * curve = NULL;
|
||||
Load_Table_Desc(cload,&curve);
|
||||
if (curve != NULL) {
|
||||
new_table = NEW_REF(LookupTableClass,());
|
||||
new_table->Init(name,curve);
|
||||
Add_Table(new_table);
|
||||
delete curve;
|
||||
}
|
||||
}
|
||||
_TheFileFactory->Return_File(file);
|
||||
}
|
||||
|
||||
return new_table; // constructor ref is returned to user.
|
||||
}
|
||||
|
||||
void LookupTableMgrClass::Save_Table_Desc
|
||||
(
|
||||
ChunkSaveClass & csave,
|
||||
Curve1DClass * curve,
|
||||
const Vector2 & min_corner,
|
||||
const Vector2 & max_corner
|
||||
)
|
||||
{
|
||||
// save the curve
|
||||
csave.Begin_Chunk(LOOKUPTABLE_CHUNK_CURVE);
|
||||
csave.Begin_Chunk(curve->Get_Factory().Chunk_ID());
|
||||
curve->Get_Factory().Save(csave,curve);
|
||||
csave.End_Chunk();
|
||||
csave.End_Chunk();
|
||||
|
||||
// save the extents
|
||||
csave.Begin_Chunk(LOOKUPTABLE_CHUNK_EXTENTS);
|
||||
csave.Write(&(min_corner.X),sizeof(float));
|
||||
csave.Write(&(min_corner.Y),sizeof(float));
|
||||
csave.Write(&(max_corner.X),sizeof(float));
|
||||
csave.Write(&(max_corner.Y),sizeof(float));
|
||||
csave.End_Chunk();
|
||||
}
|
||||
|
||||
void LookupTableMgrClass::Load_Table_Desc
|
||||
(
|
||||
ChunkLoadClass & cload,
|
||||
Curve1DClass ** curve_ptr,
|
||||
Vector2 * set_min_corner,
|
||||
Vector2 * set_max_corner
|
||||
)
|
||||
{
|
||||
*curve_ptr = NULL;
|
||||
PersistFactoryClass * factory;
|
||||
|
||||
float xmin,xmax;
|
||||
float ymin,ymax;
|
||||
xmin = xmax = ymin = ymax = 0.0f;
|
||||
|
||||
while (cload.Open_Chunk()) {
|
||||
switch(cload.Cur_Chunk_ID()) {
|
||||
case LOOKUPTABLE_CHUNK_CURVE:
|
||||
cload.Open_Chunk();
|
||||
factory = SaveLoadSystemClass::Find_Persist_Factory(cload.Cur_Chunk_ID());
|
||||
WWASSERT(factory != NULL);
|
||||
if (factory != NULL) {
|
||||
*curve_ptr = (Curve1DClass *)factory->Load(cload);
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
break;
|
||||
case LOOKUPTABLE_CHUNK_EXTENTS:
|
||||
cload.Read(&xmin,sizeof(xmin));
|
||||
cload.Read(&ymin,sizeof(ymin));
|
||||
cload.Read(&xmax,sizeof(xmax));
|
||||
cload.Read(&ymax,sizeof(ymax));
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
if (set_min_corner != NULL) {
|
||||
set_min_corner->Set(xmin,ymin);
|
||||
}
|
||||
if (set_max_corner != NULL) {
|
||||
set_max_corner->Set(xmax,ymax);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
161
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/lookuptable.h
Normal file
161
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/lookuptable.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 : WWPhys *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/wwmath/lookuptable.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 4/18/00 1:20p $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#ifndef LOOKUPTABLE_H
|
||||
#define LOOKUPTABLE_H
|
||||
|
||||
#include "always.h"
|
||||
#include "simplevec.h"
|
||||
#include "wwstring.h"
|
||||
#include "refcount.h"
|
||||
#include "multilist.h"
|
||||
#include "wwmath.h"
|
||||
|
||||
|
||||
class Vector2;
|
||||
class Curve1DClass;
|
||||
class ChunkSaveClass;
|
||||
class ChunkLoadClass;
|
||||
|
||||
|
||||
/**
|
||||
** LookupTableClass
|
||||
** This class contains the tabulated values for a function.
|
||||
*/
|
||||
class LookupTableClass : public RefCountClass, public MultiListObjectClass
|
||||
{
|
||||
public:
|
||||
|
||||
LookupTableClass(int sample_count = 256);
|
||||
virtual ~LookupTableClass(void);
|
||||
|
||||
void Init(const char * name,Curve1DClass * curve);
|
||||
float Get_Value(float input);
|
||||
float Get_Value_Quick(float input);
|
||||
const char * Get_Name(void) { return Name; }
|
||||
protected:
|
||||
|
||||
StringClass Name; // name of this table, if it came from a file, this is also the filename
|
||||
float MinInputValue;
|
||||
float MaxInputValue;
|
||||
float OOMaxMinusMin;
|
||||
SimpleVecClass<float> OutputSamples;
|
||||
|
||||
};
|
||||
|
||||
inline float LookupTableClass::Get_Value(float input)
|
||||
{
|
||||
if (input <= MinInputValue) {
|
||||
return OutputSamples[0];
|
||||
}
|
||||
if (input >= MaxInputValue) {
|
||||
return OutputSamples[OutputSamples.Length()-1];
|
||||
}
|
||||
|
||||
float normalized_input = (float)(OutputSamples.Length()-1) * (input - MinInputValue) * OOMaxMinusMin;
|
||||
float input0 = WWMath::Floor(normalized_input);
|
||||
|
||||
int index0 = WWMath::Float_To_Long(input0);
|
||||
int index1 = index0+1;
|
||||
float lerp = normalized_input - input0;
|
||||
|
||||
return OutputSamples[index0] + lerp * (OutputSamples[index1] - OutputSamples[index0]);
|
||||
}
|
||||
|
||||
inline float LookupTableClass::Get_Value_Quick(float input)
|
||||
{
|
||||
if (input <= MinInputValue) {
|
||||
return OutputSamples[0];
|
||||
}
|
||||
if (input >= MaxInputValue) {
|
||||
return OutputSamples[OutputSamples.Length()-1];
|
||||
}
|
||||
|
||||
int index = (OutputSamples.Length()-1) * WWMath::Float_To_Long((input - MinInputValue) * OOMaxMinusMin);
|
||||
return OutputSamples[index];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** LookupTableMgrClass
|
||||
** This class tracks all of the LookupTableClass's that have been loaded or installed.
|
||||
** LookupTables can be created using the "SimpleGraph" tool. It basically allows you
|
||||
** to edit a curve which will be used to generate the table. These curves are stored
|
||||
** in .TBL files.
|
||||
**
|
||||
** NOTE: Use the SimpleGraph program to create lookup tables! Then just ask for them
|
||||
** by filename and it will load the table for you (unless it is already loaded).
|
||||
**
|
||||
** NOTE: I add a table called "DefaultTable" so that you can revert to that if
|
||||
** your table isn't found.
|
||||
*/
|
||||
class LookupTableMgrClass
|
||||
{
|
||||
public:
|
||||
LookupTableMgrClass(void);
|
||||
~LookupTableMgrClass(void);
|
||||
|
||||
// init and shutdown are automatically called from WWMath::Init, WWMath::Shutdown...
|
||||
static void Init(void);
|
||||
static void Shutdown(void);
|
||||
|
||||
static bool Add_Table(LookupTableClass * table);
|
||||
static bool Remove_Table(LookupTableClass * table);
|
||||
static LookupTableClass * Get_Table(const char * name,bool try_to_load = true);
|
||||
|
||||
static void Save_Table_Desc( ChunkSaveClass & csave,
|
||||
Curve1DClass * curve,
|
||||
const Vector2 & min,
|
||||
const Vector2 & max );
|
||||
|
||||
static void Load_Table_Desc( ChunkLoadClass & cload,
|
||||
Curve1DClass ** curve_ptr,
|
||||
Vector2 * set_min = NULL,
|
||||
Vector2 * set_max = NULL );
|
||||
|
||||
static void Reset(void);
|
||||
|
||||
protected:
|
||||
|
||||
static RefMultiListClass<LookupTableClass> Tables;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // LOOKUPTABLE_H
|
||||
393
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix3.cpp
Normal file
393
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix3.cpp
Normal file
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/matrix3.cpp $*
|
||||
* *
|
||||
* Org Author:: Greg_h *
|
||||
* *
|
||||
* Author : Kenny Mitchell *
|
||||
* *
|
||||
* $Modtime:: 06/26/02 4:04p $*
|
||||
* *
|
||||
* $Revision:: 17 $*
|
||||
* *
|
||||
* 06/26/02 KM Matrix name change to avoid MAX conflicts *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "matrix3.h"
|
||||
#include "matrix3d.h"
|
||||
#include "matrix4.h"
|
||||
#include "quat.h"
|
||||
|
||||
|
||||
/*
|
||||
** Some pre-initialized Matrix3x3's
|
||||
*/
|
||||
const Matrix3x3 Matrix3x3::Identity
|
||||
(
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
const Matrix3x3 Matrix3x3::RotateX90
|
||||
(
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 0.0, -1.0,
|
||||
0.0, 1.0, 0.0
|
||||
);
|
||||
|
||||
const Matrix3x3 Matrix3x3::RotateX180
|
||||
(
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, -1.0, 0.0,
|
||||
0.0, 0.0, -1.0
|
||||
);
|
||||
|
||||
const Matrix3x3 Matrix3x3::RotateX270
|
||||
(
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
0.0, -1.0, 0.0
|
||||
);
|
||||
|
||||
const Matrix3x3 Matrix3x3::RotateY90
|
||||
(
|
||||
0.0, 0.0, 1.0,
|
||||
0.0, 1.0, 0.0,
|
||||
-1.0, 0.0, 0.0
|
||||
);
|
||||
|
||||
const Matrix3x3 Matrix3x3::RotateY180
|
||||
(
|
||||
-1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, -1.0
|
||||
);
|
||||
|
||||
const Matrix3x3 Matrix3x3::RotateY270
|
||||
(
|
||||
0.0, 0.0, -1.0,
|
||||
0.0, 1.0, 0.0,
|
||||
1.0, 0.0, 0.0
|
||||
);
|
||||
|
||||
const Matrix3x3 Matrix3x3::RotateZ90
|
||||
(
|
||||
0.0, -1.0, 0.0,
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
const Matrix3x3 Matrix3x3::RotateZ180
|
||||
(
|
||||
-1.0, 0.0, 0.0,
|
||||
0.0, -1.0, 0.0,
|
||||
0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
const Matrix3x3 Matrix3x3::RotateZ270
|
||||
(
|
||||
0.0, 1.0, 0.0,
|
||||
-1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix3x3::Matrix3x3 -- Convert a Matrix3D (fake 4x4) to a Matrix3x3 *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
Matrix3x3::Matrix3x3(const Matrix3D & m)
|
||||
{
|
||||
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||||
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||||
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||||
}
|
||||
|
||||
Matrix3x3::Matrix3x3(const Matrix4x4 & m)
|
||||
{
|
||||
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||||
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||||
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||||
}
|
||||
|
||||
void Matrix3x3::Set(const Matrix3D & m)
|
||||
{
|
||||
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||||
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||||
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||||
}
|
||||
|
||||
void Matrix3x3::Set(const Matrix4x4 & m)
|
||||
{
|
||||
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||||
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||||
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||||
}
|
||||
|
||||
void Matrix3x3::Set(const Quaternion & q)
|
||||
{
|
||||
Row[0][0] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]));
|
||||
Row[0][1] = (float)(2.0 * (q[0] * q[1] - q[2] * q[3]));
|
||||
Row[0][2] = (float)(2.0 * (q[2] * q[0] + q[1] * q[3]));
|
||||
|
||||
Row[1][0] = (float)(2.0 * (q[0] * q[1] + q[2] * q[3]));
|
||||
Row[1][1] = (float)(1.0 - 2.0f * (q[2] * q[2] + q[0] * q[0]));
|
||||
Row[1][2] = (float)(2.0 * (q[1] * q[2] - q[0] * q[3]));
|
||||
|
||||
Row[2][0] = (float)(2.0 * (q[2] * q[0] - q[1] * q[3]));
|
||||
Row[2][1] = (float)(2.0 * (q[1] * q[2] + q[0] * q[3]));
|
||||
Row[2][2] =(float)(1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]));
|
||||
}
|
||||
|
||||
|
||||
Matrix3x3 & Matrix3x3::operator = (const Matrix3D & m)
|
||||
{
|
||||
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||||
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||||
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix3x3 & Matrix3x3::operator = (const Matrix4x4 & m)
|
||||
{
|
||||
Row[0].Set(m[0][0],m[0][1],m[0][2]);
|
||||
Row[1].Set(m[1][0],m[1][1],m[1][2]);
|
||||
Row[2].Set(m[2][0],m[2][1],m[2][2]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Matrix3x3::Multiply(const Matrix3D & a, const Matrix3x3 & b,Matrix3x3 * res)
|
||||
{
|
||||
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||||
|
||||
(*res)[0][0] = ROWCOL(0,0);
|
||||
(*res)[0][1] = ROWCOL(0,1);
|
||||
(*res)[0][2] = ROWCOL(0,2);
|
||||
|
||||
(*res)[1][0] = ROWCOL(1,0);
|
||||
(*res)[1][1] = ROWCOL(1,1);
|
||||
(*res)[1][2] = ROWCOL(1,2);
|
||||
|
||||
(*res)[2][0] = ROWCOL(2,0);
|
||||
(*res)[2][1] = ROWCOL(2,1);
|
||||
(*res)[2][2] = ROWCOL(2,2);
|
||||
|
||||
#undef ROWCOL
|
||||
}
|
||||
|
||||
void Matrix3x3::Multiply(const Matrix3x3 & a, const Matrix3D & b,Matrix3x3 * res)
|
||||
{
|
||||
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||||
|
||||
(*res)[0][0] = ROWCOL(0,0);
|
||||
(*res)[0][1] = ROWCOL(0,1);
|
||||
(*res)[0][2] = ROWCOL(0,2);
|
||||
|
||||
(*res)[1][0] = ROWCOL(1,0);
|
||||
(*res)[1][1] = ROWCOL(1,1);
|
||||
(*res)[1][2] = ROWCOL(1,2);
|
||||
|
||||
(*res)[2][0] = ROWCOL(2,0);
|
||||
(*res)[2][1] = ROWCOL(2,1);
|
||||
(*res)[2][2] = ROWCOL(2,2);
|
||||
|
||||
#undef ROWCOL
|
||||
}
|
||||
|
||||
Matrix3x3 operator * (const Matrix3D & a, const Matrix3x3 & b)
|
||||
{
|
||||
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||||
|
||||
return Matrix3x3(
|
||||
Vector3(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2) ),
|
||||
Vector3(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2) ),
|
||||
Vector3(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2) )
|
||||
);
|
||||
|
||||
#undef ROWCOL
|
||||
}
|
||||
|
||||
Matrix3x3 operator * (const Matrix3x3 & a, const Matrix3D & b)
|
||||
{
|
||||
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||||
|
||||
return Matrix3x3(
|
||||
Vector3(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2) ),
|
||||
Vector3(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2) ),
|
||||
Vector3(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2) )
|
||||
);
|
||||
|
||||
#undef ROWCOL
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
void Matrix3x3::Compute_Jacobi_Rotation(int i,int j,Matrix3x3 * r,Matrix3x3 * rinv)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Matrix3x3::Symmetric_Eigen_Solve(void)
|
||||
{
|
||||
Matrix3x3 eigen_vals = *this;
|
||||
Matrix3x3 eigen_vecs(1);
|
||||
|
||||
Matrix3x3 jr,jrinv;
|
||||
|
||||
while (!done) {
|
||||
eigen_vals.Compute_Jacobi_Rotation(i,j,&jr,&jrinv);
|
||||
eigen_vals = jr * (eigenvals) * jrinv;
|
||||
eigen_vecs = eigen_vecs * jr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Done! Eigen values are the diagonals of
|
||||
** the eigen_vals matrix and the eigen vectors
|
||||
** are the columns of the eigen_vecs matrix
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void Matrix3x3::Multiply(const Matrix3x3 & A,const Matrix3x3 & B,Matrix3x3 * set_res)
|
||||
{
|
||||
Matrix3x3 tmp;
|
||||
Matrix3x3 * Aptr;
|
||||
float tmp1,tmp2,tmp3;
|
||||
|
||||
// Check for aliased parameters, copy the 'A' matrix into a temporary if the
|
||||
// result is going into 'A'. (in this case, this function is no better than
|
||||
// the overloaded C++ operator...)
|
||||
if (set_res == &A) {
|
||||
tmp = A;
|
||||
Aptr = &tmp;
|
||||
} else {
|
||||
Aptr = (Matrix3x3 *)&A;
|
||||
}
|
||||
|
||||
tmp1 = B[0][0];
|
||||
tmp2 = B[1][0];
|
||||
tmp3 = B[2][0];
|
||||
|
||||
(*set_res)[0][0] = (float)((*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3);
|
||||
(*set_res)[1][0] = (float)((*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3);
|
||||
(*set_res)[2][0] = (float)((*Aptr)[2][0]*tmp1 + (*Aptr)[2][1]*tmp2 + (*Aptr)[2][2]*tmp3);
|
||||
|
||||
tmp1 = B[0][1];
|
||||
tmp2 = B[1][1];
|
||||
tmp3 = B[2][1];
|
||||
|
||||
(*set_res)[0][1] = (float)((*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3);
|
||||
(*set_res)[1][1] = (float)((*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3);
|
||||
(*set_res)[2][1] = (float)((*Aptr)[2][0]*tmp1 + (*Aptr)[2][1]*tmp2 + (*Aptr)[2][2]*tmp3);
|
||||
|
||||
tmp1 = B[0][2];
|
||||
tmp2 = B[1][2];
|
||||
tmp3 = B[2][2];
|
||||
|
||||
(*set_res)[0][2] = (float)((*Aptr)[0][0]*tmp1 + (*Aptr)[0][1]*tmp2 + (*Aptr)[0][2]*tmp3);
|
||||
(*set_res)[1][2] = (float)((*Aptr)[1][0]*tmp1 + (*Aptr)[1][1]*tmp2 + (*Aptr)[1][2]*tmp3);
|
||||
(*set_res)[2][2] = (float)((*Aptr)[2][0]*tmp1 + (*Aptr)[2][1]*tmp2 + (*Aptr)[2][2]*tmp3);
|
||||
}
|
||||
|
||||
int Matrix3x3::Is_Orthogonal(void) const
|
||||
{
|
||||
Vector3 x(Row[0].X,Row[0].Y,Row[0].Z);
|
||||
Vector3 y(Row[1].X,Row[1].Y,Row[1].Z);
|
||||
Vector3 z(Row[2].X,Row[2].Y,Row[2].Z);
|
||||
|
||||
if (Vector3::Dot_Product(x,y) > WWMATH_EPSILON) return 0;
|
||||
if (Vector3::Dot_Product(y,z) > WWMATH_EPSILON) return 0;
|
||||
if (Vector3::Dot_Product(z,x) > WWMATH_EPSILON) return 0;
|
||||
|
||||
if (WWMath::Fabs(x.Length() - 1.0f) > WWMATH_EPSILON) return 0;
|
||||
if (WWMath::Fabs(y.Length() - 1.0f) > WWMATH_EPSILON) return 0;
|
||||
if (WWMath::Fabs(z.Length() - 1.0f) > WWMATH_EPSILON) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Matrix3x3::Re_Orthogonalize(void)
|
||||
{
|
||||
Vector3 x(Row[0][0],Row[0][1],Row[0][2]);
|
||||
Vector3 y(Row[1][0],Row[1][1],Row[1][2]);
|
||||
Vector3 z;
|
||||
|
||||
Vector3::Cross_Product(x,y,&z);
|
||||
Vector3::Cross_Product(z,x,&y);
|
||||
|
||||
float len = x.Length();
|
||||
if (len < WWMATH_EPSILON) {
|
||||
Make_Identity();
|
||||
return;
|
||||
} else {
|
||||
x /= len;
|
||||
}
|
||||
|
||||
len = y.Length();
|
||||
if (len < WWMATH_EPSILON) {
|
||||
Make_Identity();
|
||||
return;
|
||||
} else {
|
||||
y /= len;
|
||||
}
|
||||
|
||||
len = z.Length();
|
||||
if (len < WWMATH_EPSILON) {
|
||||
Make_Identity();
|
||||
return;
|
||||
} else {
|
||||
z /= len;
|
||||
}
|
||||
|
||||
Row[0][0] = x.X;
|
||||
Row[0][1] = x.Y;
|
||||
Row[0][2] = x.Z;
|
||||
|
||||
Row[1][0] = y.X;
|
||||
Row[1][1] = y.Y;
|
||||
Row[1][2] = y.Z;
|
||||
|
||||
Row[2][0] = z.X;
|
||||
Row[2][1] = z.Y;
|
||||
Row[2][2] = z.Z;
|
||||
}
|
||||
|
||||
1032
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix3.h
Normal file
1032
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix3.h
Normal file
File diff suppressed because it is too large
Load Diff
1242
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix3d.cpp
Normal file
1242
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix3d.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1818
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix3d.h
Normal file
1818
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix3d.h
Normal file
File diff suppressed because it is too large
Load Diff
197
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix4.cpp
Normal file
197
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix4.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/matrix4.cpp $*
|
||||
* *
|
||||
* Org Author:: Greg_h *
|
||||
* *
|
||||
* Author : Kenny_m *
|
||||
* *
|
||||
* $Modtime:: 06/26/02 4:04p $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
* 06/26/02 KM Matrix name change to avoid MAX conflicts *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Matrix4x4::Multiply -- Multiply two Matrix4x4's together *
|
||||
* Matrix4x4::Multiply -- Multiply a Matrix3D * Matrix4x4 *
|
||||
* Matrix4x4::Multiply -- Multiply a Matrix4x4 * Matrix3D *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "matrix4.h"
|
||||
#include <assert.h>
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Multiply -- Multiply two Matrix4x4's together *
|
||||
* *
|
||||
* INPUT: *
|
||||
* a - first operand *
|
||||
* b - second operand *
|
||||
* res - pointer to matrix to store the result in (must not point to a or b) *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/13/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void Matrix4x4::Multiply(const Matrix4x4 &a,const Matrix4x4 &b,Matrix4x4 * res)
|
||||
{
|
||||
assert(res != &a);
|
||||
assert(res != &b);
|
||||
|
||||
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]*b[3][j]
|
||||
|
||||
(*res)[0][0] = ROWCOL(0,0);
|
||||
(*res)[0][1] = ROWCOL(0,1);
|
||||
(*res)[0][2] = ROWCOL(0,2);
|
||||
(*res)[0][3] = ROWCOL(0,3);
|
||||
|
||||
(*res)[1][0] = ROWCOL(1,0);
|
||||
(*res)[1][1] = ROWCOL(1,1);
|
||||
(*res)[1][2] = ROWCOL(1,2);
|
||||
(*res)[1][3] = ROWCOL(1,3);
|
||||
|
||||
(*res)[2][0] = ROWCOL(2,0);
|
||||
(*res)[2][1] = ROWCOL(2,1);
|
||||
(*res)[2][2] = ROWCOL(2,2);
|
||||
(*res)[2][3] = ROWCOL(2,3);
|
||||
|
||||
(*res)[3][0] = ROWCOL(3,0);
|
||||
(*res)[3][1] = ROWCOL(3,1);
|
||||
(*res)[3][2] = ROWCOL(3,2);
|
||||
(*res)[3][3] = ROWCOL(3,3);
|
||||
|
||||
#undef ROWCOL
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Multiply -- Multiply a Matrix3D * Matrix4x4 *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/13/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
void Matrix4x4::Multiply(const Matrix3D &a,const Matrix4x4 &b,Matrix4x4 * res)
|
||||
{
|
||||
assert(res != &b);
|
||||
|
||||
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]*b[3][j]
|
||||
|
||||
(*res)[0][0] = ROWCOL(0,0);
|
||||
(*res)[0][1] = ROWCOL(0,1);
|
||||
(*res)[0][2] = ROWCOL(0,2);
|
||||
(*res)[0][3] = ROWCOL(0,3);
|
||||
|
||||
(*res)[1][0] = ROWCOL(1,0);
|
||||
(*res)[1][1] = ROWCOL(1,1);
|
||||
(*res)[1][2] = ROWCOL(1,2);
|
||||
(*res)[1][3] = ROWCOL(1,3);
|
||||
|
||||
(*res)[2][0] = ROWCOL(2,0);
|
||||
(*res)[2][1] = ROWCOL(2,1);
|
||||
(*res)[2][2] = ROWCOL(2,2);
|
||||
(*res)[2][3] = ROWCOL(2,3);
|
||||
|
||||
(*res)[3][0] = b[3][0]; // last row of a is 0,0,0,1
|
||||
(*res)[3][1] = b[3][1]; // this leaves the last row of b unchanged
|
||||
(*res)[3][2] = b[3][2];
|
||||
(*res)[3][3] = b[3][3];
|
||||
|
||||
#undef ROWCOL
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Multiply -- Multiply a Matrix4x4 * Matrix3D *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*=============================================================================================*/
|
||||
void Matrix4x4::Multiply(const Matrix4x4 & a,const Matrix3D & b,Matrix4x4 * res)
|
||||
{
|
||||
assert(res != &a);
|
||||
|
||||
// ROWCOL multiplies a row of 'a' by one of the first three columns of 'b' (4th entry in b is zero)
|
||||
// ROWCOL4 multiplies a row of 'a' by the fourth column of 'b' (4th entry in b is one)
|
||||
|
||||
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||||
#define ROWCOL4(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]
|
||||
|
||||
(*res)[0][0] = ROWCOL(0,0);
|
||||
(*res)[0][1] = ROWCOL(0,1);
|
||||
(*res)[0][2] = ROWCOL(0,2);
|
||||
(*res)[0][3] = ROWCOL4(0,3);
|
||||
|
||||
(*res)[1][0] = ROWCOL(1,0);
|
||||
(*res)[1][1] = ROWCOL(1,1);
|
||||
(*res)[1][2] = ROWCOL(1,2);
|
||||
(*res)[1][3] = ROWCOL4(1,3);
|
||||
|
||||
(*res)[2][0] = ROWCOL(2,0);
|
||||
(*res)[2][1] = ROWCOL(2,1);
|
||||
(*res)[2][2] = ROWCOL(2,2);
|
||||
(*res)[2][3] = ROWCOL4(2,3);
|
||||
|
||||
(*res)[3][0] = ROWCOL(3,0);
|
||||
(*res)[3][1] = ROWCOL(3,1);
|
||||
(*res)[3][2] = ROWCOL(3,2);
|
||||
(*res)[3][3] = ROWCOL4(3,3);
|
||||
|
||||
#undef ROWCOL
|
||||
#undef ROWCOL4
|
||||
}
|
||||
|
||||
int operator == (const Matrix4x4 & a, const Matrix4x4 & b)
|
||||
{
|
||||
unsigned* m1=(unsigned*)&a;
|
||||
unsigned* m2=(unsigned*)&b;
|
||||
unsigned res=0;
|
||||
for (int i=0;i<4;++i) {
|
||||
res|=*m1++^*m2++;
|
||||
res|=*m1++^*m2++;
|
||||
res|=*m1++^*m2++;
|
||||
res|=*m1++^*m2++;
|
||||
}
|
||||
return !res;
|
||||
}
|
||||
|
||||
int operator != (const Matrix4x4 & a, const Matrix4x4 & b)
|
||||
{
|
||||
return (!(a == b));
|
||||
}
|
||||
|
||||
848
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix4.h
Normal file
848
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/matrix4.h
Normal file
@@ -0,0 +1,848 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/matrix4.h 20 10/04/01 10:33a Greg_h $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : WW3D *
|
||||
* *
|
||||
* File Name : MATRIX4.H *
|
||||
* *
|
||||
* Org Programmer : Greg Hjelstrom *
|
||||
* *
|
||||
* Author : Kenny Mitchell *
|
||||
* *
|
||||
* Start Date : 06/02/97 *
|
||||
* *
|
||||
* Last Update : June 6, 2002 [KM] *
|
||||
* *
|
||||
* 06/26/02 KM Matrix name change to avoid MAX conflicts *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Matrix4x4::Matrix4x4 -- Constructor, optionally initialize to Identitiy matrix *
|
||||
* Matrix4x4::Matrix4x4 -- Copy Constructor *
|
||||
* Matrix4x4::Matrix4x4 -- Convert a Matrix3D (fake 4x4) to a Matrix4x4 *
|
||||
* Matrix4x4::Matrix4x4 -- Constructor *
|
||||
* Matrix4x4::Make_Identity -- Initializes the matrix to Identity *
|
||||
* Matrix4x4::Init -- Initializes from the contents of the give Matrix3D *
|
||||
* Matrix4x4::Init -- Initializes the rows from the given Vector4s *
|
||||
* Matrix4x4::Init -- Initializes the rows from the given 16 floats *
|
||||
* Matrix4x4::Init_Ortho -- Initialize to an orthographic projection matrix *
|
||||
* Matrix4x4::Init_Perspective -- Initialize to a perspective projection matrix *
|
||||
* Matrix4x4::Init_Perspective -- Initialize to a perspective projection matrix *
|
||||
* Matrix4x4::Transpose -- Returns transpose of the matrix *
|
||||
* Matrix4x4::Inverse -- returns the inverse of the matrix *
|
||||
* Matrix4x4::operator = -- assignment operator *
|
||||
* Matrix4x4::operator += -- "plus equals" operator *
|
||||
* Matrix4x4::operator -= -- "minus equals" operator *
|
||||
* Matrix4x4::operator *= -- "times equals" operator *
|
||||
* Matrix4x4::operator /= -- "divide equals" operator *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MATRIX4_H
|
||||
#define MATRIX4_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector4.h"
|
||||
#include "matrix3d.h"
|
||||
#include "matrix3.h"
|
||||
|
||||
|
||||
class Matrix4x4
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
** Constructors
|
||||
*/
|
||||
Matrix4x4(void) {};
|
||||
Matrix4x4(const Matrix4x4 & m);
|
||||
|
||||
WWINLINE explicit Matrix4x4(bool identity);
|
||||
WWINLINE explicit Matrix4x4(const Matrix3D & m);
|
||||
WWINLINE explicit Matrix4x4(const Matrix3x3 & m);
|
||||
WWINLINE explicit Matrix4x4(const Vector4 & v0, const Vector4 & v1, const Vector4 & v2, const Vector4 & v3);
|
||||
WWINLINE explicit Matrix4x4( float m11,float m12,float m13,float m14,
|
||||
float m21,float m22,float m23,float m24,
|
||||
float m31,float m32,float m33,float m34,
|
||||
float m41,float m42,float m43,float m44 );
|
||||
|
||||
WWINLINE void Make_Identity(void);
|
||||
WWINLINE void Init(const Matrix3D & m);
|
||||
WWINLINE void Init(const Matrix3x3 & m);
|
||||
WWINLINE void Init(const Vector4 & v0, const Vector4 & v1, const Vector4 & v2, const Vector4 & v3);
|
||||
WWINLINE void Init( float m11,float m12,float m13,float m14,
|
||||
float m21,float m22,float m23,float m24,
|
||||
float m31,float m32,float m33,float m34,
|
||||
float m41,float m42,float m43,float m44 );
|
||||
|
||||
/*
|
||||
** Projection matrices. The znear and zfar parameters are positive values indicating the
|
||||
** distance from the camera to the z clipping planes. See implementations for more info.
|
||||
*/
|
||||
WWINLINE void Init_Ortho(float left,float right,float bottom,float top,float znear,float zfar);
|
||||
WWINLINE void Init_Perspective(float hfov,float vfov,float znear,float zfar);
|
||||
WWINLINE void Init_Perspective(float left,float right,float bottom,float top,float znear,float zfar);
|
||||
|
||||
/*
|
||||
** Access operators
|
||||
*/
|
||||
WWINLINE Vector4 & operator [] (int i) { return Row[i]; }
|
||||
WWINLINE const Vector4 & operator [] (int i) const { return Row[i]; }
|
||||
|
||||
/*
|
||||
** Transpose and Inverse
|
||||
*/
|
||||
WWINLINE Matrix4x4 Transpose(void) const;
|
||||
WWINLINE Matrix4x4 Inverse(void) const;
|
||||
|
||||
/*
|
||||
** Assignment operators
|
||||
*/
|
||||
WWINLINE Matrix4x4 & operator = (const Matrix4x4 & m);
|
||||
WWINLINE Matrix4x4 & operator += (const Matrix4x4 & m);
|
||||
WWINLINE Matrix4x4 & operator -= (const Matrix4x4 & m);
|
||||
WWINLINE Matrix4x4 & operator *= (float d);
|
||||
WWINLINE Matrix4x4 & operator /= (float d);
|
||||
|
||||
/*
|
||||
** Negation
|
||||
*/
|
||||
WWINLINE friend Matrix4x4 operator - (const Matrix4x4& a);
|
||||
|
||||
/*
|
||||
** Scalar multiplication and division
|
||||
*/
|
||||
WWINLINE friend Matrix4x4 operator * (const Matrix4x4& a,float d);
|
||||
WWINLINE friend Matrix4x4 operator * (float d,const Matrix4x4& a);
|
||||
WWINLINE friend Matrix4x4 operator / (const Matrix4x4& a,float d);
|
||||
|
||||
/*
|
||||
** matrix addition
|
||||
*/
|
||||
WWINLINE friend Matrix4x4 operator + (const Matrix4x4& a, const Matrix4x4& b);
|
||||
WWINLINE friend Matrix4x4 Add(const Matrix4x4& a);
|
||||
|
||||
/*
|
||||
** matrix subtraction
|
||||
*/
|
||||
WWINLINE friend Matrix4x4 operator - (const Matrix4x4 & a, const Matrix4x4 & b);
|
||||
WWINLINE friend Matrix4x4 Subtract(const Matrix4x4 & a, const Matrix4x4 & b);
|
||||
|
||||
/*
|
||||
** matrix multiplication
|
||||
*/
|
||||
WWINLINE friend Matrix4x4 operator * (const Matrix4x4 & a, const Matrix4x4 & b);
|
||||
WWINLINE friend Matrix4x4 Multiply(const Matrix4x4 & a, const Matrix4x4 & b);
|
||||
WWINLINE friend Matrix4x4 operator * (const Matrix4x4 & a, const Matrix3D & b);
|
||||
WWINLINE friend Matrix4x4 operator * (const Matrix3D & a, const Matrix4x4 & b);
|
||||
|
||||
/*
|
||||
** Comparison operators
|
||||
*/
|
||||
friend int operator == (const Matrix4x4 & a, const Matrix4x4 & b);
|
||||
friend int operator != (const Matrix4x4 & a, const Matrix4x4 & b);
|
||||
|
||||
/*
|
||||
** Swap two matrices in place
|
||||
*/
|
||||
WWINLINE friend void Swap(Matrix4x4 & a,Matrix4x4 & b);
|
||||
|
||||
/*
|
||||
** Linear Transforms
|
||||
*/
|
||||
WWINLINE friend Vector4 operator * (const Matrix4x4 & a, const Vector4 & v);
|
||||
WWINLINE friend Vector4 operator * (const Matrix4x4 & a, const Vector3 & v);
|
||||
|
||||
/*
|
||||
** Matrix multiplication without temporaries...
|
||||
*/
|
||||
static void Multiply(const Matrix4x4 &A,const Matrix4x4 &B,Matrix4x4 * set_result);
|
||||
static void Multiply(const Matrix3D &A,const Matrix4x4 &B,Matrix4x4 * set_result);
|
||||
static void Multiply(const Matrix4x4 &A,const Matrix3D &B,Matrix4x4 * set_result);
|
||||
|
||||
static WWINLINE void Transform_Vector(const Matrix4x4 & tm,const Vector3 & in,Vector3 * out);
|
||||
static WWINLINE void Transform_Vector(const Matrix4x4 & tm,const Vector3 & in,Vector4 * out);
|
||||
static WWINLINE void Transform_Vector(const Matrix4x4 & tm,const Vector4 & in,Vector4 * out);
|
||||
|
||||
protected:
|
||||
|
||||
Vector4 Row[4];
|
||||
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Matrix4x4 -- Constructor, optionally initialize to Identitiy matrix *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4::Matrix4x4(bool identity)
|
||||
{
|
||||
if (identity) {
|
||||
Make_Identity();
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Matrix4x4 -- Copy Constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4::Matrix4x4(const Matrix4x4 & m)
|
||||
{
|
||||
Row[0] = m.Row[0]; Row[1] = m.Row[1]; Row[2] = m.Row[2]; Row[3] = m.Row[3];
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Matrix4x4 -- Convert a Matrix3D (fake 4x4) to a Matrix4x4 *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4::Matrix4x4(const Matrix3D & m)
|
||||
{
|
||||
Init(m);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Matrix4x4 -- Constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4::Matrix4x4(const Vector4 & r0, const Vector4 & r1, const Vector4 & r2, const Vector4 & r3)
|
||||
{
|
||||
Init(r0,r1,r2,r3);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Matrix4x4 -- Constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/06/2001 NH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4::Matrix4x4(float m11,float m12,float m13,float m14, float m21,float m22,float m23,float m24,
|
||||
float m31,float m32,float m33,float m34, float m41,float m42,float m43,float m44 )
|
||||
{
|
||||
Init(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Make_Identity -- Initializes the matrix to Identity *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/5/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Matrix4x4::Make_Identity(void)
|
||||
{
|
||||
Row[0].Set(1.0,0.0,0.0,0.0);
|
||||
Row[1].Set(0.0,1.0,0.0,0.0);
|
||||
Row[2].Set(0.0,0.0,1.0,0.0);
|
||||
Row[3].Set(0.0,0.0,0.0,1.0);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Init -- Initializes from the contents of the give Matrix3D *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/5/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Matrix4x4::Init(const Matrix3D & m)
|
||||
{
|
||||
Row[0] = m[0]; Row[1] = m[1]; Row[2] = m[2]; Row[3] = Vector4(0.0,0.0,0.0,1.0);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Init -- Initializes the rows from the given Vector4s *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/5/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Matrix4x4::Init(const Vector4 & r0, const Vector4 & r1, const Vector4 & r2, const Vector4 & r3)
|
||||
{
|
||||
Row[0] = r0; Row[1] = r1; Row[2] = r2; Row[3] = r3;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Init -- Initializes the rows from the given 16 floats *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/6/01 NH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Matrix4x4::Init(float m11,float m12,float m13,float m14, float m21,float m22,float m23,float m24,
|
||||
float m31,float m32,float m33,float m34, float m41,float m42,float m43,float m44)
|
||||
{
|
||||
Row[0].Set(m11,m12,m13,m14);
|
||||
Row[1].Set(m21,m22,m23,m24);
|
||||
Row[2].Set(m31,m32,m33,m34);
|
||||
Row[3].Set(m41,m42,m43,m44);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Init_Ortho -- Initialize to an orthographic projection matrix *
|
||||
* *
|
||||
* You can find the formulas for this in the appendix of the OpenGL programming guide. Also *
|
||||
* this happens to be the same convention used by Surrender. *
|
||||
* *
|
||||
* The result of this projection will be that points inside the volume will have all coords *
|
||||
* between -1 and +1. A point at znear will project to z=-1. A point at zfar will project *
|
||||
* to z=+1... *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* Note that the znear and zfar parameters are positive distances to the clipping planes *
|
||||
* even though in the camera coordinate system, the clipping planes are at negative z *
|
||||
* coordinates. This holds for all of the projection initializations and is consistent *
|
||||
* with OpenGL's convention. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/5/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Matrix4x4::Init_Ortho
|
||||
(
|
||||
float left,
|
||||
float right,
|
||||
float bottom,
|
||||
float top,
|
||||
float znear,
|
||||
float zfar
|
||||
)
|
||||
{
|
||||
assert(znear >= 0.0f);
|
||||
assert(zfar > znear);
|
||||
|
||||
Make_Identity();
|
||||
Row[0][0] = 2.0f / (right - left);
|
||||
Row[0][3] = -(right + left) / (right - left);
|
||||
Row[1][1] = 2.0f / (top - bottom);
|
||||
Row[1][3] = -(top + bottom) / (top - bottom);
|
||||
Row[2][2] = -2.0f / (zfar - znear);
|
||||
Row[2][3] = -(zfar + znear) / (zfar - znear);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Init_Perspective -- Initialize to a perspective projection matrix *
|
||||
* *
|
||||
* You can find the formulas for this matrix in the appendix of the OpenGL programming guide. *
|
||||
* Also, this happens to be the same convention used by Surrender. *
|
||||
* *
|
||||
* The result of this projection will be that points inside the volume will have all coords *
|
||||
* between -1 and +1. A point at znear will project to z=-1. A point at zfar will project *
|
||||
* to z=+1... *
|
||||
* *
|
||||
* INPUT: *
|
||||
* hfov - horizontal field of view (in radians) *
|
||||
* vfov - vertical field of view (in radians) *
|
||||
* znear - distance to near z clipping plane (positive) *
|
||||
* zfar - distance to the far z clipping plane (positive) *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* Note that the znear and zfar parameters are positive distances to the clipping planes *
|
||||
* even though in the camera coordinate system, the clipping planes are at negative z *
|
||||
* coordinates. This holds for all of the projection initializations and is consistent *
|
||||
* with OpenGL's convention. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/5/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Matrix4x4::Init_Perspective(float hfov,float vfov,float znear,float zfar)
|
||||
{
|
||||
assert(znear > 0.0f);
|
||||
assert(zfar > znear);
|
||||
|
||||
Make_Identity();
|
||||
Row[0][0] = static_cast<float>(1.0 / tan(hfov*0.5));
|
||||
Row[1][1] = static_cast<float>(1.0 / tan(vfov*0.5));
|
||||
Row[2][2] = -(zfar + znear) / (zfar - znear);
|
||||
Row[2][3] = static_cast<float>(-(2.0*zfar*znear) / (zfar - znear));
|
||||
Row[3][2] = -1.0f;
|
||||
Row[3][3] = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Init_Perspective -- Initialize to a perspective projection matrix *
|
||||
* *
|
||||
* You can find the formulas for this matrix in the appendix of the OpenGL programming guide. *
|
||||
* Also, this happens to be the same convention used by Surrender. *
|
||||
* *
|
||||
* The result of this projection will be that points inside the volume will have all coords *
|
||||
* between -1 and +1. A point at znear will project to z=-1. A point at zfar will project *
|
||||
* to z=+1... *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* left - min x coordinate of near clip plane *
|
||||
* right - max x coordinate of near clip plane *
|
||||
* bottom - min y coordinate of near clip plane *
|
||||
* top - max y coordinate of near clip plane *
|
||||
* znear - distance to near Z clipping plane *
|
||||
* zfar - distance to far Z clipping plane *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* Note that the znear and zfar parameters are positive distances to the clipping planes *
|
||||
* even though in the camera coordinate system, the clipping planes are at negative z *
|
||||
* coordinates. This holds for all of the projection initializations and is consistent *
|
||||
* with OpenGL's convention. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/5/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Matrix4x4::Init_Perspective
|
||||
(
|
||||
float left,
|
||||
float right,
|
||||
float bottom,
|
||||
float top,
|
||||
float znear,
|
||||
float zfar
|
||||
)
|
||||
{
|
||||
assert(znear > 0.0f);
|
||||
assert(zfar > 0.0f);
|
||||
|
||||
Make_Identity();
|
||||
Row[0][0] = static_cast<float>(2.0*znear / (right - left));
|
||||
Row[0][2] = (right + left) / (right - left);
|
||||
Row[1][1] = static_cast<float>(2.0*znear / (top - bottom));
|
||||
Row[1][2] = (top + bottom) / (top - bottom);
|
||||
Row[2][2] = -(zfar + znear) / (zfar - znear);
|
||||
Row[2][3] = static_cast<float>(-(2.0*zfar*znear) / (zfar - znear));
|
||||
Row[3][2] = -1.0f;
|
||||
Row[3][3] = 0.0f;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Transpose -- Returns transpose of the matrix *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4 Matrix4x4::Transpose() const
|
||||
{
|
||||
return Matrix4x4(
|
||||
Vector4(Row[0][0], Row[1][0], Row[2][0], Row[3][0]),
|
||||
Vector4(Row[0][1], Row[1][1], Row[2][1], Row[3][1]),
|
||||
Vector4(Row[0][2], Row[1][2], Row[2][2], Row[3][2]),
|
||||
Vector4(Row[0][3], Row[1][3], Row[2][3], Row[3][3])
|
||||
);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::Inverse -- returns the inverse of the matrix *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4 Matrix4x4::Inverse() const // Gauss-Jordan elimination with partial pivoting
|
||||
{
|
||||
WWASSERT_PRINT(0,"Matrix4x4::Inverse does not work, re-implement!");
|
||||
|
||||
Matrix4x4 a(*this); // As a evolves from original mat into identity
|
||||
Matrix4x4 b(true); // b evolves from identity into inverse(a)
|
||||
int i, j, i1;
|
||||
|
||||
// Loop over cols of a from left to right, eliminating above and below diagonal
|
||||
for (j=0; j<4; j++) {
|
||||
|
||||
// Find largest pivot in column j among rows j..3
|
||||
i1 = j;
|
||||
for (i=j+1; i<4; i++) {
|
||||
if (WWMath::Fabs(a[i][j]) > WWMath::Fabs(a[i1][j])) {
|
||||
i1 = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap rows i1 and j in a and b to put pivot on diagonal
|
||||
Swap(a.Row[i1], a.Row[j]);
|
||||
Swap(b.Row[i1], b.Row[j]);
|
||||
|
||||
// Scale row j to have a unit diagonal
|
||||
if (a[j][j]==0.) {
|
||||
//ALGEBRA_ERROR("Matrix4x4::inverse: singular matrix; can't invert\n");
|
||||
}
|
||||
b.Row[j] /= a.Row[j][j];
|
||||
a.Row[j] /= a.Row[j][j];
|
||||
|
||||
// Eliminate off-diagonal elems in col j of a, doing identical ops to b
|
||||
for (i=0; i<4; i++) {
|
||||
if (i != j) {
|
||||
b.Row[i] -= a[i][j] * b.Row[j];
|
||||
a.Row[i] -= a[i][j] * a.Row[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::operator = -- assignment operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4 & Matrix4x4::operator = (const Matrix4x4 & m)
|
||||
{
|
||||
Row[0] = m.Row[0]; Row[1] = m.Row[1]; Row[2] = m.Row[2]; Row[3] = m.Row[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::operator += -- "plus equals" operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4& Matrix4x4::operator += (const Matrix4x4 & m)
|
||||
{
|
||||
Row[0] += m.Row[0]; Row[1] += m.Row[1]; Row[2] += m.Row[2]; Row[3] += m.Row[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::operator-= -- "minus equals" operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4& Matrix4x4::operator -= (const Matrix4x4 & m)
|
||||
{
|
||||
Row[0] -= m.Row[0]; Row[1] -= m.Row[1]; Row[2] -= m.Row[2]; Row[3] -= m.Row[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::operator *= -- "times equals" operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4& Matrix4x4::operator *= (float d)
|
||||
{
|
||||
Row[0] *= d; Row[1] *= d; Row[2] *= d; Row[3] *= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Matrix4x4::operator /= -- "divide equals" operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Matrix4x4& Matrix4x4::operator /= (float d)
|
||||
{
|
||||
float ood = d;
|
||||
Row[0] *= ood; Row[1] *= ood; Row[2] *= ood; Row[3] *= ood;
|
||||
return *this;
|
||||
}
|
||||
|
||||
WWINLINE Matrix4x4 operator - (const Matrix4x4 & a)
|
||||
{
|
||||
return Matrix4x4(-a.Row[0], -a.Row[1], -a.Row[2], -a.Row[3]);
|
||||
}
|
||||
|
||||
WWINLINE Matrix4x4 operator * (const Matrix4x4 & a, float d)
|
||||
{
|
||||
return Matrix4x4(a.Row[0] * d, a.Row[1] * d, a.Row[2] * d, a.Row[3] * d);
|
||||
}
|
||||
|
||||
WWINLINE Matrix4x4 operator * (float d, const Matrix4x4 & a)
|
||||
{
|
||||
return a*d;
|
||||
}
|
||||
|
||||
WWINLINE Matrix4x4 operator / (const Matrix4x4 & a, float d)
|
||||
{
|
||||
float ood = 1.0f / d;
|
||||
return Matrix4x4(a.Row[0] * ood, a.Row[1] * ood, a.Row[2] * ood, a.Row[3] * ood);
|
||||
}
|
||||
|
||||
/*
|
||||
** matrix addition
|
||||
*/
|
||||
WWINLINE Matrix4x4 operator + (const Matrix4x4 & a, const Matrix4x4 & b)
|
||||
{
|
||||
return Matrix4x4(
|
||||
a.Row[0] + b.Row[0],
|
||||
a.Row[1] + b.Row[1],
|
||||
a.Row[2] + b.Row[2],
|
||||
a.Row[3] + b.Row[3]
|
||||
);
|
||||
}
|
||||
|
||||
WWINLINE Matrix4x4 Add(const Matrix4x4 & a, const Matrix4x4 & b)
|
||||
{ return a+b; }
|
||||
|
||||
/*
|
||||
** matrix subtraction
|
||||
*/
|
||||
WWINLINE Matrix4x4 operator - (const Matrix4x4 & a, const Matrix4x4 & b)
|
||||
{
|
||||
return Matrix4x4(
|
||||
a.Row[0] - b.Row[0],
|
||||
a.Row[1] - b.Row[1],
|
||||
a.Row[2] - b.Row[2],
|
||||
a.Row[3] - b.Row[3]
|
||||
);
|
||||
}
|
||||
|
||||
WWINLINE Matrix4x4 Subtract(const Matrix4x4 & a, const Matrix4x4 & b)
|
||||
{ return a-b; }
|
||||
|
||||
/*
|
||||
** matrix multiplication
|
||||
*/
|
||||
WWINLINE Matrix4x4 operator * (const Matrix4x4 & a, const Matrix4x4 & b)
|
||||
{
|
||||
#define ROWCOL(i, j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]*b[3][j]
|
||||
|
||||
return Matrix4x4(
|
||||
Vector4(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2), ROWCOL(0,3)),
|
||||
Vector4(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2), ROWCOL(1,3)),
|
||||
Vector4(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2), ROWCOL(2,3)),
|
||||
Vector4(ROWCOL(3,0), ROWCOL(3,1), ROWCOL(3,2), ROWCOL(3,3))
|
||||
);
|
||||
|
||||
#undef ROWCOL
|
||||
}
|
||||
|
||||
WWINLINE Matrix4x4 Multiply(const Matrix4x4 & a, const Matrix4x4 & b)
|
||||
{ return a*b; }
|
||||
|
||||
WWINLINE Matrix4x4 operator * (const Matrix4x4 & a, const Matrix3D & b)
|
||||
{
|
||||
// This function hand coded to handle the last row of b as 0,0,0,1
|
||||
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||||
#define ROWCOL_LAST(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]
|
||||
return Matrix4x4(
|
||||
Vector4(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2), ROWCOL_LAST(0,3)),
|
||||
Vector4(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2), ROWCOL_LAST(1,3)),
|
||||
Vector4(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2), ROWCOL_LAST(2,3)),
|
||||
Vector4(ROWCOL(3,0), ROWCOL(3,1), ROWCOL(3,2), ROWCOL_LAST(3,3))
|
||||
);
|
||||
#undef ROWCOL
|
||||
#undef ROWCOL_LAST
|
||||
}
|
||||
|
||||
WWINLINE Matrix4x4 operator * (const Matrix3D & a, const Matrix4x4 & b)
|
||||
{
|
||||
// This function hand coded to handle the last row of a as 0,0,0,1
|
||||
#define ROWCOL(i,j) a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j] + a[i][3]*b[3][j]
|
||||
return Matrix4x4(
|
||||
Vector4(ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2), ROWCOL(0,3)),
|
||||
Vector4(ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2), ROWCOL(1,3)),
|
||||
Vector4(ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2), ROWCOL(2,3)),
|
||||
Vector4(b[3][0], b[3][1], b[3][2], b[3][3])
|
||||
);
|
||||
#undef ROWCOL
|
||||
}
|
||||
|
||||
/*
|
||||
** Multiply a Matrix4x4 by a Vector3 (assumes w=1.0!!!). Yeilds a Vector4 result
|
||||
*/
|
||||
WWINLINE Vector4 operator * (const Matrix4x4 & a, const Vector3 & v) {
|
||||
return Vector4(
|
||||
a[0][0] * v[0] + a[0][1] * v[1] + a[0][2] * v[2] + a[0][3] * 1.0f,
|
||||
a[1][0] * v[0] + a[1][1] * v[1] + a[1][2] * v[2] + a[1][3] * 1.0f,
|
||||
a[2][0] * v[0] + a[2][1] * v[1] + a[2][2] * v[2] + a[2][3] * 1.0f,
|
||||
a[3][0] * v[0] + a[3][1] * v[1] + a[3][2] * v[2] + a[3][3] * 1.0f
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
** Multiply a Matrix4x4 by a Vector4
|
||||
*/
|
||||
WWINLINE Vector4 operator * (const Matrix4x4 & a, const Vector4 & v) {
|
||||
return Vector4(
|
||||
a[0][0] * v[0] + a[0][1] * v[1] + a[0][2] * v[2] + a[0][3] * v[3],
|
||||
a[1][0] * v[0] + a[1][1] * v[1] + a[1][2] * v[2] + a[1][3] * v[3],
|
||||
a[2][0] * v[0] + a[2][1] * v[1] + a[2][2] * v[2] + a[2][3] * v[3],
|
||||
a[3][0] * v[0] + a[3][1] * v[1] + a[3][2] * v[2] + a[3][3] * v[3]
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
** Multiply a Matrix4x4 by a Vector4
|
||||
*/
|
||||
WWINLINE void Matrix4x4::Transform_Vector(const Matrix4x4 & A,const Vector3 & in,Vector3 * out)
|
||||
{
|
||||
Vector3 tmp;
|
||||
Vector3 * v;
|
||||
|
||||
// check for aliased parameters
|
||||
if (out == &in) {
|
||||
tmp = in;
|
||||
v = &tmp;
|
||||
} else {
|
||||
v = (Vector3 *)∈ // whats the right way to do this...
|
||||
}
|
||||
|
||||
out->X = (A[0][0] * v->X + A[0][1] * v->Y + A[0][2] * v->Z + A[0][3]);
|
||||
out->Y = (A[1][0] * v->X + A[1][1] * v->Y + A[1][2] * v->Z + A[1][3]);
|
||||
out->Z = (A[2][0] * v->X + A[2][1] * v->Y + A[2][2] * v->Z + A[2][3]);
|
||||
}
|
||||
|
||||
|
||||
WWINLINE void Matrix4x4::Transform_Vector(const Matrix4x4 & A,const Vector3 & in,Vector4 * out)
|
||||
{
|
||||
out->X = (A[0][0] * in.X + A[0][1] * in.Y + A[0][2] * in.Z + A[0][3]);
|
||||
out->Y = (A[1][0] * in.X + A[1][1] * in.Y + A[1][2] * in.Z + A[1][3]);
|
||||
out->Z = (A[2][0] * in.X + A[2][1] * in.Y + A[2][2] * in.Z + A[2][3]);
|
||||
out->W = 1.0f;
|
||||
}
|
||||
|
||||
WWINLINE void Matrix4x4::Transform_Vector(const Matrix4x4 & A,const Vector4 & in,Vector4 * out)
|
||||
{
|
||||
Vector4 tmp;
|
||||
Vector4 * v;
|
||||
|
||||
// check for aliased parameters
|
||||
if (out == &in) {
|
||||
tmp = in;
|
||||
v = &tmp;
|
||||
} else {
|
||||
v = (Vector4 *)∈ // whats the right way to do this...
|
||||
}
|
||||
|
||||
out->X = (A[0][0] * v->X + A[0][1] * v->Y + A[0][2] * v->Z + A[0][3] * v->W);
|
||||
out->Y = (A[1][0] * v->X + A[1][1] * v->Y + A[1][2] * v->Z + A[1][3] * v->W);
|
||||
out->Z = (A[2][0] * v->X + A[2][1] * v->Y + A[2][2] * v->Z + A[2][3] * v->W);
|
||||
out->W = (A[3][0] * v->X + A[3][1] * v->Y + A[3][2] * v->Z + A[3][3] * v->W);
|
||||
}
|
||||
|
||||
|
||||
#endif /*MATRIX4_H*/
|
||||
243
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/normalcone.h
Normal file
243
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/normalcone.h
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 : G *
|
||||
* *
|
||||
* $Archive:: /G/WWMath/normalcone.h $*
|
||||
* *
|
||||
* $Author:: Eric_c $*
|
||||
* *
|
||||
* $Modtime:: 11/01/99 2:44p $*
|
||||
* *
|
||||
* $Revision:: 8 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
/*
|
||||
** The NormalCone is a class used to represent a cone of unit length. It can be used to
|
||||
** loosely represent a collection of other normals allowing backface culling to be
|
||||
** performed at a heirarchial level rather than at a triangle level.
|
||||
**
|
||||
** The term 'NormalCone' is a bit of a misnomer; it is really a circular portion of a sphere.
|
||||
** -ehc
|
||||
*/
|
||||
|
||||
#ifndef NORMALCONE_H
|
||||
#define NORMALCONE_H
|
||||
|
||||
#include "vector3.h"
|
||||
#include "matrix3.h"
|
||||
|
||||
class NormalCone : public Vector3
|
||||
{
|
||||
public:
|
||||
|
||||
NormalCone() {}
|
||||
|
||||
NormalCone(const Vector3 & normal, float angle = 1.0f)
|
||||
: Vector3(normal),
|
||||
Angle(angle)
|
||||
{}
|
||||
|
||||
void Set(const Vector3 & normal, float angle = 1.0f)
|
||||
{
|
||||
Vector3::Set(normal);
|
||||
Angle = angle;
|
||||
}
|
||||
|
||||
void Set(const NormalCone & src)
|
||||
{
|
||||
Set(src, src.Angle);
|
||||
}
|
||||
|
||||
// return true if this object has degenerated into a sphere.
|
||||
inline bool Complete_Sphere()
|
||||
{
|
||||
return (Angle - WWMATH_EPSILON) <= -1.0f;
|
||||
}
|
||||
|
||||
// find the two vectors on the edge of the cone residing on the same plane as the input vector.
|
||||
// Note: these two Get_Coplanar functions return floats in an attempt to reduce float/int CPU state changes...
|
||||
inline float Get_Coplanar_Normals(const Vector3 & Input, Vector3 & Output1, Vector3 & Output2) const;
|
||||
|
||||
// find the two vectors on the edge of the cone residing on the same plane as the input vector and their dot products with the input.
|
||||
inline float Get_Coplanar_Normals_And_Dots(const Vector3 & Input, Vector3 & Output1, Vector3 & Output2, float & dot1, float & dot2) const;
|
||||
|
||||
// evaluate the input vector, expanding the angle of the cone and recalculating the
|
||||
// new center vector as needed.
|
||||
inline void Merge(const Vector3 & Input);
|
||||
|
||||
// merge the input normal cone's coplanar normals with this object.
|
||||
inline void Merge(const NormalCone & Input);
|
||||
|
||||
// this function returns the dot product between the input vector and the nearest coplanar normal
|
||||
// contained by the cone.
|
||||
// If the input vector is also contained by the cone, the result is always 1.0f.
|
||||
// Note that in the case of a complete sphere, the nearest coplanar normal will be pointing in
|
||||
// the opposite direction of the input vector.
|
||||
inline float Smallest_Dot_Product(const Vector3 & Input);
|
||||
|
||||
// this value is the dot product of the edge of the cone and the center of the cone.
|
||||
// A value of 1.0f indicates that it is a degenerate cone which is basically a cone with radius zero.
|
||||
// A value of zero indicates the cone is actually hemisphere.
|
||||
// A value of -1.0f indicates that it is a complete sphere.
|
||||
float Angle;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// find the two vectors on the edge of the cone residing on the same plane as the input vector.
|
||||
inline float NormalCone::Get_Coplanar_Normals(const Vector3 & Input, Vector3 & Output1, Vector3 & Output2) const
|
||||
{
|
||||
// get the cross product of the existing normal and the new one
|
||||
Vector3 cross;
|
||||
Vector3::Cross_Product(Input, *this, & cross);
|
||||
|
||||
float length = cross.Length2();
|
||||
if(length < WWMATH_EPSILON)
|
||||
return 0.0f;
|
||||
|
||||
length = sqrt(length);
|
||||
cross /= length;
|
||||
|
||||
// Make a matrix3 which uses it as an axis of rotation and
|
||||
// rotate this about that axis twice, once +Angle, once -Angle.
|
||||
float radians = (1.0f - Angle) * WWMATH_PI * 0.5f;
|
||||
Matrix3 m1(cross, radians);
|
||||
Matrix3 m2(cross, -radians);
|
||||
|
||||
Matrix3::Rotate_Vector(m1, *this, & Output1);
|
||||
Matrix3::Rotate_Vector(m2, *this, & Output2);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
inline float NormalCone::Get_Coplanar_Normals_And_Dots(const Vector3 & Input, Vector3 & Output1, Vector3 & Output2, float & Dot1, float & Dot2) const
|
||||
{
|
||||
float length = Get_Coplanar_Normals(Input, Output1, Output2);
|
||||
|
||||
if(length < WWMATH_EPSILON)
|
||||
return 0.0f;
|
||||
|
||||
// get the dot products of the new normal with the two coplanar normals and the current average
|
||||
Dot1 = Vector3::Dot_Product(Input, Output1);
|
||||
Dot2 = Vector3::Dot_Product(Input, Output2);
|
||||
return length;
|
||||
}
|
||||
|
||||
// evaluate the input vector, expanding the angle of the cone and recalculating the
|
||||
// new center vector as needed.
|
||||
inline void NormalCone::Merge(const Vector3 & Input)
|
||||
{
|
||||
// early exit if this normal cone has already turned into a complete sphere.
|
||||
if(Complete_Sphere())
|
||||
return;
|
||||
|
||||
// get the dot of the new vector with the current center vector
|
||||
float dot0 = Vector3::Dot_Product(Input, * this) + WWMATH_EPSILON;
|
||||
|
||||
// if the dot value is greater than the existing cone angle, then the new vector fits
|
||||
// within the cone, so return.
|
||||
if(dot0 >= Angle)
|
||||
return;
|
||||
|
||||
// get the two normals found in the cone which are coplanar to the one passed to this function.
|
||||
Vector3 normal1, normal2;
|
||||
float dot1, dot2;
|
||||
if(Get_Coplanar_Normals_And_Dots(Input, normal1, normal2, dot1, dot2) <= WWMATH_EPSILON)
|
||||
return;
|
||||
|
||||
// test the case where the current average has a lower dot than either of the coplanar normals.
|
||||
// If true, this means that the object now represents a complete sphere with normals facing every
|
||||
// direction.
|
||||
if((dot0 < dot1) && (dot0 < dot2))
|
||||
{
|
||||
Angle = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// the smaller of the dot values we have is going to indicate which of the two coplanar normals to use
|
||||
// for averaging into the new center normal.
|
||||
if(dot1 < dot2)
|
||||
Set(Input + normal1, dot1);
|
||||
else
|
||||
Set(Input + normal2, dot2);
|
||||
|
||||
// if the angle is < 0, reverse the direction of the averaged normal since we have constructed
|
||||
// something more like a sphere with a cone shape taken out of it (a negative cone).
|
||||
if(Angle < WWMATH_EPSILON)
|
||||
*this *= -1;
|
||||
|
||||
Normalize();
|
||||
}
|
||||
|
||||
|
||||
// merge the input normal cone's coplanar normals with this object.
|
||||
inline void NormalCone::Merge(const NormalCone & Input)
|
||||
{
|
||||
Vector3 n1, n2;
|
||||
|
||||
if(Input.Get_Coplanar_Normals(*this, n1,n2) >= WWMATH_EPSILON)
|
||||
{
|
||||
Merge(n1);
|
||||
Merge(n2);
|
||||
}
|
||||
}
|
||||
|
||||
// this function returns the dot product between the input vector and the nearest coplanar normal
|
||||
// contained by the cone.
|
||||
// If the input vector is also contained by the cone, the result is always 1.0f.
|
||||
// Note that in the case of a complete sphere, the nearest coplanar normal will be pointing in
|
||||
// the opposite direction of the input vector.
|
||||
inline float NormalCone::Smallest_Dot_Product(const Vector3 & Input)
|
||||
{
|
||||
if(Complete_Sphere())
|
||||
return -1.0f;
|
||||
|
||||
// get the dot of the new vector with the current center vector
|
||||
float dot0 = Vector3::Dot_Product(Input, * this);
|
||||
|
||||
// if the negative dot value is greater than the existing cone angle, then the new vector is
|
||||
// parallel to one of the vectors contained in the cone but in negative
|
||||
// direction, so return -1.0f
|
||||
if(-dot0 + WWMATH_EPSILON >= Angle)
|
||||
return -1.0f;
|
||||
|
||||
// if the dot value is greater than the existing cone angle, then the new vector is
|
||||
// parallel to one of the vectors contained in the cone, so return 1.0f
|
||||
if(dot0 + WWMATH_EPSILON >= Angle)
|
||||
return 1.0f;
|
||||
|
||||
// get the two normals found in the cone which are coplanar to the one passed to this function.
|
||||
Vector3 normal1, normal2;
|
||||
float dot1, dot2;
|
||||
Get_Coplanar_Normals_And_Dots(Input, normal1, normal2, dot1, dot2);
|
||||
|
||||
// return the smaller of the two dot products
|
||||
if(dot1 < dot2)
|
||||
return dot1;
|
||||
return dot2;
|
||||
}
|
||||
|
||||
#endif
|
||||
791
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/obbox.cpp
Normal file
791
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/obbox.cpp
Normal file
@@ -0,0 +1,791 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/obbox.cpp $*
|
||||
* *
|
||||
* Org Author:: Greg_h *
|
||||
* *
|
||||
* Author : Kenny Mitchell *
|
||||
* *
|
||||
* $Modtime:: 06/26/02 4:04p $*
|
||||
* *
|
||||
* $Revision:: 24 $*
|
||||
* *
|
||||
* 06/26/02 KM Matrix name change to avoid MAX conflicts *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* OBBoxClass::OBBoxClass -- Constructor that computes the box for a set of point *
|
||||
* OBBoxClass::Init_From_Box_Points -- Create an OBBox from 8 corners of a box *
|
||||
* OBBoxClass::Init_Random -- initalize a random oriented box *
|
||||
* Oriented_Boxes_Intersect_On_Axis -- test if two boxes intersect on given axis *
|
||||
* Oriented_Boxes_Intersect -- test if two oriented boxes intersect *
|
||||
* Oriented_Boxes_Collide_On_Axis -- test if two boxes collide on the given axis *
|
||||
* Oriented_Boxes_Collide -- test if two oriented boxes collide *
|
||||
* Oriented_Box_Intersects_Tri_On_Axis -- tests if the box and tri intersect on the axis *
|
||||
* Oriented_Box_Intersects_Tri -- tests if the given box and tri intersect *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "obbox.h"
|
||||
#include "matrix3.h"
|
||||
#include "vector3.h"
|
||||
#include "aabox.h"
|
||||
#include "tri.h"
|
||||
#include "plane.h"
|
||||
#include "quat.h"
|
||||
#include <assert.h>
|
||||
//#include <stdlib.h>
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* OBBoxClass::OBBoxClass -- Constructor that computes the box for a set of points *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 2/4/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
OBBoxClass::OBBoxClass(const Vector3 * /*points*/, int /*n*/)
|
||||
{
|
||||
// TODO: IMPLEMENT THIS!!!
|
||||
assert(0);
|
||||
|
||||
#if 0
|
||||
int i;
|
||||
|
||||
// compute mean and covariances of points
|
||||
float xsum = 0.0f, ysum = 0.0f, zsum = 0.0f;;
|
||||
float xxsum = 0.0f, xysum = 0.0f, xzsum = 0.0f;
|
||||
float yysum = 0.0f, yzsum = 0.0f, zzsum = 0.0f;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
xsum += points[i].X;
|
||||
ysum += points[i].Y;
|
||||
zsum += points[i].Z;
|
||||
|
||||
xxsum += points[i].X * points[i].X;
|
||||
xysum += points[i].X * points[i].Y;
|
||||
xzsum += points[i].X * points[i].Z;
|
||||
|
||||
yysum += points[i].Y * points[i].Y;
|
||||
yzsum += points[i].Y * points[i].Z;
|
||||
zzsum += points[i].Z * points[i].Z;
|
||||
}
|
||||
|
||||
float xmean = xsum/n;
|
||||
float ymean = ysum/n;
|
||||
float zmean = zsum/n;
|
||||
float xxcov = xxsum/n - xmean*xmean;
|
||||
float xycov = xysum/n - xmean*ymean;
|
||||
float xzcov = xzsum/n - xmean*zmean;
|
||||
float yycov = yysum/n - ymean*ymean;
|
||||
float yzcov = yzsum/n - ymean*zmean;
|
||||
float zzcov = zzsum/n - zmean*zmean;
|
||||
|
||||
// compute eigenvectors for covariance matrix,
|
||||
// these will be the axes.
|
||||
mgcEigen eig(3);
|
||||
eig.Matrix(0,0) = xxcov;
|
||||
eig.Matrix(0,1) = xycov;
|
||||
eig.Matrix(0,2) = xzcov;
|
||||
eig.Matrix(1,0) = xycov;
|
||||
eig.Matrix(1,1) = yycov;
|
||||
eig.Matrix(1,2) = yzcov;
|
||||
eig.Matrix(2,0) = xzcov;
|
||||
eig.Matrix(2,1) = yzcov;
|
||||
eig.Matrix(2,2) = zzcov;
|
||||
|
||||
eig.EigenStuff3();
|
||||
Point3 U =
|
||||
{
|
||||
eig.Eigenvector(0,0),
|
||||
eig.Eigenvector(1,0),
|
||||
eig.Eigenvector(2,0)
|
||||
};
|
||||
Point3 V =
|
||||
{
|
||||
eig.Eigenvector(0,1),
|
||||
eig.Eigenvector(1,1),
|
||||
eig.Eigenvector(2,1)
|
||||
};
|
||||
Point3 W =
|
||||
{
|
||||
eig.Eigenvector(0,2),
|
||||
eig.Eigenvector(1,2),
|
||||
eig.Eigenvector(2,2)
|
||||
};
|
||||
|
||||
// box center is the mean of the distribution
|
||||
box.center.x = xmean;
|
||||
box.center.y = ymean;
|
||||
box.center.z = zmean;
|
||||
|
||||
|
||||
// Box axes are the eigenvectors of the covariance matrix with
|
||||
// adjusted lengths to enclose the points. If U, V, and W are the
|
||||
// eigenvectors, C is the center of the box, and X is a point in
|
||||
// the input list, then X = C + a*U + b*V + c*W. The box extent is
|
||||
// determined by max|a|, max|b|, and max|c|. The box axes are then
|
||||
// defined to be (max|a|)*U and (max|b|)*V. Note that since U and V
|
||||
// are unit length and orthogonal, a = Dot(U,X-C), b = Dot(V,X-C),
|
||||
// and c = Dot(W,X-C).
|
||||
float amax = 0.0f, bmax = 0.0f, cmax = 0.0f;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
float dx = pt[i].x - box.center.x;
|
||||
float dy = pt[i].y - box.center.y;
|
||||
float dz = pt[i].z - box.center.z;
|
||||
float absdot = float(WWMath::Fabs(U.x*dx+U.y*dy+U.z*dz));
|
||||
if ( absdot > amax )
|
||||
amax = absdot;
|
||||
absdot = float(WWMath::Fabs(V.x*dx+V.y*dy+V.z*dz));
|
||||
if ( absdot > bmax )
|
||||
bmax = absdot;
|
||||
absdot = float(WWMath::Fabs(W.x*dx+W.y*dy+W.z*dz));
|
||||
if ( absdot > cmax )
|
||||
cmax = absdot;
|
||||
}
|
||||
|
||||
box.axis[0].x = amax*U.x;
|
||||
box.axis[0].y = amax*U.y;
|
||||
box.axis[0].z = amax*U.z;
|
||||
box.axis[1].x = bmax*V.x;
|
||||
box.axis[1].y = bmax*V.y;
|
||||
box.axis[1].z = bmax*V.z;
|
||||
box.axis[2].x = cmax*W.x;
|
||||
box.axis[2].y = cmax*W.y;
|
||||
box.axis[2].z = cmax*W.z;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* OBBoxClass::Init_From_Box_Points -- Create an OBBox from 8 corners of a box *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 2/24/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void OBBoxClass::Init_From_Box_Points(Vector3 * points,int num)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
/*
|
||||
** This function assumes that you pass in 8 points which are the
|
||||
** corners of a rectangular solid. Bad things will happen if
|
||||
** this assumption is not true!!!!
|
||||
*/
|
||||
assert(num == 8);
|
||||
|
||||
/*
|
||||
** Just pick the first point as the preliminary center. Compute
|
||||
** vectors from this point to each of the other points
|
||||
*/
|
||||
Vector3 dp[8];
|
||||
for (i=1;i<num;i++) {
|
||||
dp[i] = points[i] - points[0];
|
||||
}
|
||||
|
||||
/*
|
||||
** Find the shortest two candidate axes. Then the
|
||||
** third axis will be the cross product of these two.
|
||||
*/
|
||||
for (i=1;i<num;i++) {
|
||||
for (j=i+1;j<num;j++) {
|
||||
if (dp[j].Length2() < dp[i].Length2()) {
|
||||
Swap(dp[j],dp[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 axis0,axis1,axis2;
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
axis0 = Normalize(dp[1]);
|
||||
axis1 = Normalize(dp[2]);
|
||||
#else
|
||||
axis0 = dp[1]; axis0.Normalize();
|
||||
axis1 = dp[2]; axis1.Normalize();
|
||||
#endif
|
||||
Vector3::Cross_Product(axis0,axis1,&axis2);
|
||||
|
||||
Basis = Matrix3x3(axis0,axis1,axis2);
|
||||
|
||||
/*
|
||||
** Center is the average of all of the points
|
||||
*/
|
||||
Center.Set(0,0,0);
|
||||
for (i=0; i<num; i++) {
|
||||
Center += points[i];
|
||||
}
|
||||
Center.X /= num;
|
||||
Center.Y /= num;
|
||||
Center.Z /= num;
|
||||
|
||||
/*
|
||||
** Compute extents along the computed axes. This is done
|
||||
** by projecting each point onto the three axes and keeping
|
||||
** the largest projection on each.
|
||||
*/
|
||||
Extent.Set(0,0,0);
|
||||
|
||||
for (i=0; i<num; i++) {
|
||||
float dx = points[i].X - Center.X;
|
||||
float dy = points[i].Y - Center.Y;
|
||||
float dz = points[i].Z - Center.Z;
|
||||
|
||||
float xprj = float(WWMath::Fabs(axis0.X * dx + axis0.Y * dy + axis0.Z * dz));
|
||||
if (xprj > Extent.X) Extent.X = xprj;
|
||||
|
||||
float yprj = float(WWMath::Fabs(axis1.X * dx + axis1.Y * dy + axis1.Z * dz));
|
||||
if (yprj > Extent.Y) Extent.Y = yprj;
|
||||
|
||||
float zprj = float(WWMath::Fabs(axis2.X * dx + axis2.Y * dy + axis2.Z * dz));
|
||||
if (zprj > Extent.Z) Extent.Z = zprj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* OBBoxClass::Init_Random -- initalize a random oriented box *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/21/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void OBBoxClass::Init_Random(float min_extent,float max_extent)
|
||||
{
|
||||
Center.Set(0,0,0);
|
||||
|
||||
Extent.X = min_extent + WWMath::Random_Float() * (max_extent - min_extent);
|
||||
Extent.Y = min_extent + WWMath::Random_Float() * (max_extent - min_extent);
|
||||
Extent.Z = min_extent + WWMath::Random_Float() * (max_extent - min_extent);
|
||||
|
||||
Quaternion orient;
|
||||
orient.X = WWMath::Random_Float();
|
||||
orient.Y = WWMath::Random_Float();
|
||||
orient.Z = WWMath::Random_Float();
|
||||
orient.W = WWMath::Random_Float();
|
||||
orient.Normalize();
|
||||
|
||||
Basis = Build_Matrix3(orient);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Oriented_Boxes_Intersect_On_Axis -- test if two boxes intersect on given axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/7/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Oriented_Boxes_Intersect_On_Axis
|
||||
(
|
||||
const OBBoxClass & box0,
|
||||
const OBBoxClass & box1,
|
||||
const Vector3 & axis
|
||||
)
|
||||
{
|
||||
float ra,rb,rsum;
|
||||
|
||||
if (axis.Length2() < WWMATH_EPSILON) return true;
|
||||
|
||||
ra = box0.Project_To_Axis(axis);
|
||||
rb = box1.Project_To_Axis(axis);
|
||||
rsum = WWMath::Fabs(ra) + WWMath::Fabs(rb);
|
||||
|
||||
// project the center distance onto the line:
|
||||
Vector3 C = box1.Center - box0.Center;
|
||||
float cdist = Vector3::Dot_Product(axis,C);
|
||||
|
||||
if ((cdist > rsum) || (cdist < -rsum)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Oriented_Boxes_Intersect -- test if two oriented boxes intersect *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/7/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Oriented_Boxes_Intersect
|
||||
(
|
||||
const OBBoxClass & box0,
|
||||
const OBBoxClass & box1
|
||||
)
|
||||
{
|
||||
Vector3 axis;
|
||||
Vector3 A[3],B[3];
|
||||
|
||||
// vectors for the axis directions of the two boxes in world space
|
||||
A[0].Set(box0.Basis[0][0],box0.Basis[1][0],box0.Basis[2][0]);
|
||||
A[1].Set(box0.Basis[0][1],box0.Basis[1][1],box0.Basis[2][1]);
|
||||
A[2].Set(box0.Basis[0][2],box0.Basis[1][2],box0.Basis[2][2]);
|
||||
|
||||
B[0].Set(box1.Basis[0][0],box1.Basis[1][0],box1.Basis[2][0]);
|
||||
B[1].Set(box1.Basis[0][1],box1.Basis[1][1],box1.Basis[2][1]);
|
||||
B[2].Set(box1.Basis[0][2],box1.Basis[1][2],box1.Basis[2][2]);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Projecting the two boxes onto Box0's X axis. If their intervals
|
||||
// on this line do not intersect, the boxes are not intersecting.
|
||||
// Each of the tests in this function work in a similar way.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,A[0])) return false;
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,A[1])) return false;
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,A[2])) return false;
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,B[0])) return false;
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,B[1])) return false;
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,B[2])) return false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// None of the aligned axes turned out to be separating axes. Now
|
||||
// we check all combinations of cross products of the two boxes axes.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A[0],B[0],&axis);
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[0],B[1],&axis);
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[0],B[2],&axis);
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[1],B[0],&axis);
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[1],B[1],&axis);
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[1],B[2],&axis);
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[2],B[0],&axis);
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[2],B[1],&axis);
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[2],B[2],&axis);
|
||||
if (!Oriented_Boxes_Intersect_On_Axis(box0,box1,axis)) return false;
|
||||
|
||||
// None of the above tests separated the two boxes, so they are intersecting
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Oriented_Boxes_Collide_On_Axis -- test if two boxes collide on the given axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/7/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Oriented_Boxes_Collide_On_Axis
|
||||
(
|
||||
const OBBoxClass & box0,
|
||||
const Vector3 & v0,
|
||||
const OBBoxClass & box1,
|
||||
const Vector3 & v1,
|
||||
const Vector3 & axis,
|
||||
float dt
|
||||
)
|
||||
{
|
||||
float ra,rb,rsum;
|
||||
|
||||
if (axis.Length2() < WWMATH_EPSILON) return true;
|
||||
|
||||
ra = box0.Project_To_Axis(axis);
|
||||
rb = box1.Project_To_Axis(axis);
|
||||
rsum = WWMath::Fabs(ra) + WWMath::Fabs(rb);
|
||||
|
||||
// project the center distance onto the line:
|
||||
Vector3 C = box1.Center - box0.Center;
|
||||
Vector3 V = v1 - v0;
|
||||
|
||||
float cdist = Vector3::Dot_Product(axis,C);
|
||||
float vdist = cdist + dt * Vector3::Dot_Product(axis,V);
|
||||
|
||||
if ((cdist > rsum && vdist > rsum) || (cdist < -rsum && vdist < -rsum)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Oriented_Boxes_Collide -- test if two oriented boxes collide *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/7/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Oriented_Boxes_Collide
|
||||
(
|
||||
const OBBoxClass & box0,
|
||||
const Vector3 & v0,
|
||||
const OBBoxClass & box1,
|
||||
const Vector3 & v1,
|
||||
float dt
|
||||
)
|
||||
{
|
||||
bool intersect = true;
|
||||
|
||||
// variables for holding the separating axis and the projected distances
|
||||
Vector3 SepAxis;
|
||||
|
||||
// vectors for the axis directions of the two boxes in world space
|
||||
Vector3 A0(box0.Basis[0][0],box0.Basis[1][0],box0.Basis[2][0]);
|
||||
Vector3 A1(box0.Basis[0][1],box0.Basis[1][1],box0.Basis[2][1]);
|
||||
Vector3 A2(box0.Basis[0][2],box0.Basis[1][2],box0.Basis[2][2]);
|
||||
|
||||
Vector3 B0(box1.Basis[0][0],box1.Basis[1][0],box1.Basis[2][0]);
|
||||
Vector3 B1(box1.Basis[0][1],box1.Basis[1][1],box1.Basis[2][1]);
|
||||
Vector3 B2(box1.Basis[0][2],box1.Basis[1][2],box1.Basis[2][2]);
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A0
|
||||
//
|
||||
// Projecting the two boxes onto Box0's X axis. If their intervals
|
||||
// on this line do not intersect, the boxes are not intersecting!
|
||||
// Each of the tests in this function work in a similar way.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
SepAxis = A0;
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A1
|
||||
// Separating Axis is Box0's Y axis
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
SepAxis = A1;
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A2
|
||||
// Separating Axis is Box0's Z axis
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
SepAxis = A2;
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = B0
|
||||
// Separating Axis is Box1's X axis
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
SepAxis = B0;
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = B1
|
||||
// Separating Axis is Box1's Y axis
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
SepAxis = B1;
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = B2
|
||||
// Separating Axis is Box1's Z axis
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
SepAxis = B2;
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// None of the aligned axes turned out to be separating axes. Now
|
||||
// we check all combinations of cross products of the two boxes axes.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A0xB0
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A0,B0,&SepAxis);
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A0xB1
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A0,B1,&SepAxis);
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A0xB2
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A0,B2,&SepAxis);
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A1xB0
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A1,B0,&SepAxis);
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A1xB1
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A1,B1,&SepAxis);
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A1xB2
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A1,B2,&SepAxis);
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A2xB0
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A2,B0,&SepAxis);
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A2xB1
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A2,B1,&SepAxis);
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// L = A2xB2
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
Vector3::Cross_Product(A2,B2,&SepAxis);
|
||||
|
||||
if (!Oriented_Boxes_Collide_On_Axis(box0,v0,box1,v1,SepAxis,dt)) {
|
||||
intersect = false;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
return intersect;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Oriented_Box_Intersects_Tri_On_Axis -- tests if the box and tri intersect on the axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/7/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Oriented_Box_Intersects_Tri_On_Axis(const OBBoxClass & box,const TriClass & tri,Vector3 & axis)
|
||||
{
|
||||
float leb; // leading edge of box (farthest point from center)
|
||||
float lep; // leading edge of poly (closest point to center)
|
||||
float dist; // distance from box center to v0
|
||||
float tmp;
|
||||
|
||||
if (axis.Length2() < WWMATH_EPSILON) return true;
|
||||
|
||||
Vector3 D = *(tri.V[0]) - box.Center;
|
||||
Vector3 r1 = *(tri.V[1]) - *(tri.V[0]);
|
||||
Vector3 r2 = *(tri.V[2]) - *(tri.V[0]);
|
||||
|
||||
// I want the axis to point from box.center to tri.v0
|
||||
dist = Vector3::Dot_Product(D,axis);
|
||||
if (dist < 0) {
|
||||
dist = -dist;
|
||||
axis = -axis;
|
||||
}
|
||||
|
||||
// compute leading edge of the box
|
||||
leb = box.Project_To_Axis(axis);
|
||||
|
||||
// compute the leading edge of the triangle
|
||||
lep = 0;
|
||||
tmp = Vector3::Dot_Product(r1,axis); if (tmp < lep) lep = tmp;
|
||||
tmp = Vector3::Dot_Product(r2,axis); if (tmp < lep) lep = tmp;
|
||||
lep += dist;
|
||||
|
||||
if (lep >= leb) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Oriented_Box_Intersects_Tri -- tests if the given box and tri intersect *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/7/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool Oriented_Box_Intersects_Tri(const OBBoxClass & box,const TriClass & tri)
|
||||
{
|
||||
Vector3 axis;
|
||||
|
||||
// vectors for the axis directions of the two boxes in world space
|
||||
Vector3 A[3];
|
||||
Vector3 E[3];
|
||||
Vector3 normal = *tri.N;
|
||||
A[0].Set(box.Basis[0][0],box.Basis[1][0],box.Basis[2][0]);
|
||||
A[1].Set(box.Basis[0][1],box.Basis[1][1],box.Basis[2][1]);
|
||||
A[2].Set(box.Basis[0][2],box.Basis[1][2],box.Basis[2][2]);
|
||||
E[0] = *(tri.V[1]) - *(tri.V[0]);
|
||||
E[1] = *(tri.V[2]) - *(tri.V[1]);
|
||||
E[2] = *(tri.V[0]) - *(tri.V[2]);
|
||||
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,normal)) return false;
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,A[0])) return false;
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,A[1])) return false;
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,A[2])) return false;
|
||||
|
||||
Vector3::Cross_Product(A[0],E[0],&axis);
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[0],E[1],&axis);
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[0],E[2],&axis);
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[1],E[0],&axis);
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[1],E[1],&axis);
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[1],E[2],&axis);
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[2],E[0],&axis);
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[2],E[1],&axis);
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,axis)) return false;
|
||||
|
||||
Vector3::Cross_Product(A[2],E[2],&axis);
|
||||
if (!Oriented_Box_Intersects_Tri_On_Axis(box,tri,axis)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
271
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/obbox.h
Normal file
271
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/obbox.h
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/obbox.h $*
|
||||
* *
|
||||
* Org Author:: Greg_h *
|
||||
* *
|
||||
* Author : Kenny Mitchell *
|
||||
* *
|
||||
* $Modtime:: 06/26/02 4:04p $*
|
||||
* *
|
||||
* $Revision:: 24 $*
|
||||
* *
|
||||
* 06/26/02 KM Matrix name change to avoid MAX conflicts *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* OBBoxClass::Transform -- transform an oriented box *
|
||||
* OBBoxClass::Project_To_Axis -- compute projection onto the given axis *
|
||||
* OBBoxClass::Compute_Point -- computes position of a parametricly defined point *
|
||||
* OBBoxClass::Compute_Axis_Aligned_Extent -- computes extent of an AABox enclosing this box *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef OBBOX_H
|
||||
#define OBBOX_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector3.h"
|
||||
#include "matrix3.h"
|
||||
#include "matrix3d.h"
|
||||
#include "wwmath.h"
|
||||
#include "castres.h"
|
||||
|
||||
class TriClass;
|
||||
class AABoxClass;
|
||||
class PlaneClass;
|
||||
|
||||
|
||||
/*
|
||||
** OBBoxClass
|
||||
**
|
||||
** Oriented-Bounding-Box Class.
|
||||
** This is a collision box in world space.
|
||||
** Center - position of the center of the box
|
||||
** Extents - size of the box
|
||||
** Basis - rotation matrix defining the orientation of the box
|
||||
**
|
||||
** To find the world space coordinates of the "+x,+y,+z" corner of
|
||||
** the bounding box you could use this equation:
|
||||
** Vector3 corner = Center + Basis * Extent;
|
||||
*/
|
||||
class OBBoxClass
|
||||
{
|
||||
public:
|
||||
|
||||
OBBoxClass(void) { }
|
||||
|
||||
OBBoxClass(const OBBoxClass & that) :
|
||||
Basis(that.Basis),
|
||||
Center(that.Center),
|
||||
Extent(that.Extent)
|
||||
{ }
|
||||
|
||||
OBBoxClass(const Vector3 & center,const Vector3 & extent) :
|
||||
Basis(1),
|
||||
Center(center),
|
||||
Extent(extent)
|
||||
{ }
|
||||
|
||||
OBBoxClass(const Vector3 & center,const Vector3 & extent,const Matrix3x3 & basis) :
|
||||
Basis(basis),
|
||||
Center(center),
|
||||
Extent(extent)
|
||||
{ }
|
||||
|
||||
OBBoxClass(const Vector3 * points, int num_points);
|
||||
|
||||
bool operator== (const OBBoxClass &src);
|
||||
bool operator!= (const OBBoxClass &src);
|
||||
|
||||
void Init_From_Box_Points(Vector3 * points,int num_points);
|
||||
void Init_Random(float min_extent = 0.5f,float max_extent = 1.0f);
|
||||
float Project_To_Axis(const Vector3 & axis) const;
|
||||
float Volume(void) const { return 2.0*Extent.X * 2.0*Extent.Y * 2.0*Extent.Z; }
|
||||
void Compute_Point(float params[3],Vector3 * set_point) const;
|
||||
void Compute_Axis_Aligned_Extent(Vector3 * set_extent) const;
|
||||
|
||||
Matrix3x3 Basis;
|
||||
Vector3 Center;
|
||||
Vector3 Extent;
|
||||
|
||||
static void Transform(const Matrix3D & tm,const OBBoxClass & in,OBBoxClass * out);
|
||||
};
|
||||
|
||||
// Test functions: slow, easy to understand version of box intersection code :)
|
||||
bool Oriented_Boxes_Intersect(const OBBoxClass & box0,const OBBoxClass & box1);
|
||||
bool Oriented_Boxes_Collide(const OBBoxClass & box0,const Vector3 & v0,const OBBoxClass & box1,const Vector3 & v1,float dt);
|
||||
bool Oriented_Box_Intersects_Tri(const OBBoxClass & box,const TriClass & tri);
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* OBBoxClass::Project_To_Axis -- compute projection onto the given axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 2/24/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline float OBBoxClass::Project_To_Axis(const Vector3 & axis) const
|
||||
{
|
||||
float x = Extent[0] * Vector3::Dot_Product(axis,Vector3(Basis[0][0],Basis[1][0],Basis[2][0]));
|
||||
float y = Extent[1] * Vector3::Dot_Product(axis,Vector3(Basis[0][1],Basis[1][1],Basis[2][1]));
|
||||
float z = Extent[2] * Vector3::Dot_Product(axis,Vector3(Basis[0][2],Basis[1][2],Basis[2][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));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* OBBoxClass::Transform -- transform an oriented box *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 2/24/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void OBBoxClass::Transform
|
||||
(
|
||||
const Matrix3D & tm,
|
||||
const OBBoxClass & in,
|
||||
OBBoxClass * out
|
||||
)
|
||||
{
|
||||
WWASSERT(out);
|
||||
WWASSERT(out!=&in);
|
||||
|
||||
out->Extent = in.Extent;
|
||||
Matrix3D::Transform_Vector(tm,in.Center,&(out->Center));
|
||||
Matrix3x3::Multiply(tm,in.Basis,&(out->Basis));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* OBBoxClass::Compute_Point -- computes position of a parametricly defined point *
|
||||
* *
|
||||
* set_point = Center + params[0]*A0 + params[1]*A1 + params[2]*A2 *
|
||||
* *
|
||||
* INPUT: *
|
||||
* params - parametric description of a point in the box. -1 < params[i] < 1 *
|
||||
* set_point - pointer to a Vector3 to set. *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/2/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void OBBoxClass::Compute_Point(float params[3],Vector3 * set_point) const
|
||||
{
|
||||
Vector3 point = Extent;
|
||||
point.X *= params[0];
|
||||
point.Y *= params[1];
|
||||
point.Z *= params[2];
|
||||
|
||||
Matrix3x3::Rotate_Vector(Basis,point,set_point);
|
||||
Vector3::Add(Center,*set_point,set_point);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* OBBoxClass::Compute_Axis_Aligned_Extent -- computes extent of an AABox enclosing this box *
|
||||
* *
|
||||
* INPUT: *
|
||||
* set_extent - pointer to a Vector3 to put the result into *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/15/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void OBBoxClass::Compute_Axis_Aligned_Extent(Vector3 * set_extent) const
|
||||
{
|
||||
WWASSERT(set_extent != NULL);
|
||||
|
||||
// x extent is the box projected onto the x axis
|
||||
set_extent->X = WWMath::Fabs(Extent[0] * Basis[0][0]) +
|
||||
WWMath::Fabs(Extent[1] * Basis[0][1]) +
|
||||
WWMath::Fabs(Extent[2] * Basis[0][2]);
|
||||
|
||||
set_extent->Y = WWMath::Fabs(Extent[0] * Basis[1][0]) +
|
||||
WWMath::Fabs(Extent[1] * Basis[1][1]) +
|
||||
WWMath::Fabs(Extent[2] * Basis[1][2]);
|
||||
|
||||
set_extent->Z = WWMath::Fabs(Extent[0] * Basis[2][0]) +
|
||||
WWMath::Fabs(Extent[1] * Basis[2][1]) +
|
||||
WWMath::Fabs(Extent[2] * Basis[2][2]);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* OBBoxClass::operator== -- Comparison operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/21/00 PDS : Created. *
|
||||
*=============================================================================================*/
|
||||
inline bool OBBoxClass::operator== (const OBBoxClass &src)
|
||||
{
|
||||
return (Center == src.Center) && (Extent == src.Extent) && (Basis == src.Basis);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* OBBoxClass::operator!= -- Comparison operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 6/21/00 PDS : Created. *
|
||||
*=============================================================================================*/
|
||||
inline bool OBBoxClass::operator!= (const OBBoxClass &src)
|
||||
{
|
||||
return (Center != src.Center) || (Extent != src.Extent) && (Basis == src.Basis);
|
||||
}
|
||||
|
||||
#endif
|
||||
367
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/ode.cpp
Normal file
367
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/ode.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/ODE.CPP 8 7/02/99 10:32a Greg_h $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/wwmath/ODE.CPP $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 6/25/99 6:23p $*
|
||||
* *
|
||||
* $Revision:: 8 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Euler_Integrate -- uses Eulers method to integrate a system of ODE's *
|
||||
* Midpoint_Integrate -- midpoint method (Runge-Kutta 2) for integration *
|
||||
* Runge_Kutta_Integrate -- Runge Kutta 4 method *
|
||||
* Runge_Kutta5_Integrate -- 5th order Runge-Kutta *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "ode.h"
|
||||
#include <assert.h>
|
||||
|
||||
static StateVectorClass Y0;
|
||||
static StateVectorClass Y1;
|
||||
static StateVectorClass _WorkVector0;
|
||||
static StateVectorClass _WorkVector1;
|
||||
static StateVectorClass _WorkVector2;
|
||||
static StateVectorClass _WorkVector3;
|
||||
static StateVectorClass _WorkVector4;
|
||||
static StateVectorClass _WorkVector5;
|
||||
static StateVectorClass _WorkVector6;
|
||||
static StateVectorClass _WorkVector7;
|
||||
|
||||
/***********************************************************************************************
|
||||
* Euler_Solve -- uses Eulers method to integrate a system of ODE's *
|
||||
* *
|
||||
* INPUT: *
|
||||
* odesys - pointer to the ODE system to integrate *
|
||||
* dt - size of the timestep *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* state vector in odesys will be updated for the next timestep *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
* 6/25/99 GTH : Updated to the new integrator system *
|
||||
*=============================================================================================*/
|
||||
void IntegrationSystem::Euler_Integrate(ODESystemClass * sys, float dt)
|
||||
{
|
||||
WWASSERT(sys != NULL);
|
||||
|
||||
/*
|
||||
** Get the current state
|
||||
*/
|
||||
Y0.Reset();
|
||||
sys->Get_State(Y0);
|
||||
Y1.Resize(Y0.Count());
|
||||
|
||||
/*
|
||||
** make aliases to the work-vectors we need
|
||||
*/
|
||||
StateVectorClass & dydt = _WorkVector0;
|
||||
dydt.Resize(Y0.Count());
|
||||
|
||||
/*
|
||||
** Euler method, just evaluate the derivative, multiply
|
||||
** by the time-step and add to the current state vector.
|
||||
*/
|
||||
sys->Compute_Derivatives(0,NULL,&dydt);
|
||||
|
||||
Y1.Resize(Y0.Count());
|
||||
for (int i = 0; i < Y0.Count(); i++) {
|
||||
Y1[i] = Y0[i] + dydt[i] * dt;
|
||||
}
|
||||
|
||||
sys->Set_State(Y1);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Midpoint_Integrate -- midpoint method (Runge-Kutta 2) *
|
||||
* *
|
||||
* INPUT: *
|
||||
* sys - pointer to the ODE system to integrate *
|
||||
* dt - size of the timestep *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* state vector in odesys will be updated for the next timestep *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
* 6/25/99 GTH : Updated to the new integrator system *
|
||||
*=============================================================================================*/
|
||||
void IntegrationSystem::Midpoint_Integrate(ODESystemClass * sys,float dt)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
** Get the current state
|
||||
*/
|
||||
Y0.Reset();
|
||||
sys->Get_State(Y0);
|
||||
Y1.Resize(Y0.Count());
|
||||
|
||||
/*
|
||||
** make aliases to the work-vectors we need
|
||||
*/
|
||||
StateVectorClass & dydt = _WorkVector0;
|
||||
StateVectorClass & ymid = _WorkVector1;
|
||||
dydt.Resize(Y0.Count());
|
||||
ymid.Resize(Y0.Count());
|
||||
|
||||
/*
|
||||
** MidPoint method, first evaluate the derivitives of the
|
||||
** state vector just like the Euler method.
|
||||
*/
|
||||
sys->Compute_Derivatives(0.0f,NULL,&dydt);
|
||||
|
||||
/*
|
||||
** Compute the midpoint between the Euler solution and
|
||||
** the input values.
|
||||
*/
|
||||
for (i=0; i<Y0.Count(); i++) {
|
||||
ymid[i] = Y0[i] + dt * dydt[i] / 2.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
** Re-compute derivatives at this point.
|
||||
*/
|
||||
sys->Compute_Derivatives(dt/2.0f,&ymid,&dydt);
|
||||
|
||||
/*
|
||||
** Use these derivatives to compute the solution.
|
||||
*/
|
||||
for (i=0; i<Y0.Count(); i++) {
|
||||
Y1[i] = Y0[i] + dt * dydt[i];
|
||||
}
|
||||
|
||||
sys->Set_State(Y1);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Runge_Kutta_Integrate -- Runge Kutta 4 method *
|
||||
* *
|
||||
* INPUT: *
|
||||
* odesys - pointer to the ODE system to integrate *
|
||||
* dt - size of the timestep *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* state vector in odesys will be updated for the next timestep *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void IntegrationSystem::Runge_Kutta_Integrate(ODESystemClass * sys,float dt)
|
||||
{
|
||||
int i;
|
||||
float dt2 = dt / 2.0f;
|
||||
float dt6 = dt / 6.0f;
|
||||
|
||||
/*
|
||||
** Get the current state
|
||||
*/
|
||||
Y0.Reset();
|
||||
sys->Get_State(Y0);
|
||||
Y1.Resize(Y0.Count());
|
||||
|
||||
/*
|
||||
** make aliases to the work-vectors we need
|
||||
*/
|
||||
StateVectorClass & dydt = _WorkVector0;
|
||||
StateVectorClass & dym = _WorkVector1;
|
||||
StateVectorClass & dyt = _WorkVector2;
|
||||
StateVectorClass & yt = _WorkVector3;
|
||||
dydt.Resize(Y0.Count());
|
||||
dym.Resize(Y0.Count());
|
||||
dyt.Resize(Y0.Count());
|
||||
yt.Resize(Y0.Count());
|
||||
|
||||
/*
|
||||
** First Step
|
||||
*/
|
||||
sys->Compute_Derivatives(0.0f,NULL,&dydt);
|
||||
for (i=0; i<Y0.Count(); i++) {
|
||||
yt[i] = Y0[i] + dt2 * dydt[i];
|
||||
}
|
||||
|
||||
/*
|
||||
** Second Step
|
||||
*/
|
||||
sys->Compute_Derivatives(dt2, &yt, &dyt);
|
||||
for (i=0; i<Y0.Count(); i++) {
|
||||
yt[i] = Y0[i] + dt2 * dyt[i];
|
||||
}
|
||||
|
||||
/*
|
||||
** Third Step
|
||||
*/
|
||||
sys->Compute_Derivatives(dt2, &yt, &dym);
|
||||
for (i=0; i<Y0.Count(); i++) {
|
||||
yt[i] = Y0[i] + dt*dym[i];
|
||||
dym[i] += dyt[i];
|
||||
}
|
||||
|
||||
/*
|
||||
** Fourth Step
|
||||
*/
|
||||
sys->Compute_Derivatives(dt, &yt, &dyt);
|
||||
for (i=0; i<Y0.Count(); i++) {
|
||||
Y1[i] = Y0[i] + dt6 * (dydt[i] + dyt[i] + 2.0f*dym[i]);
|
||||
}
|
||||
|
||||
sys->Set_State(Y1);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Runge_Kutta5_Integrate -- 5th order Runge-Kutta *
|
||||
* *
|
||||
* INPUT: *
|
||||
* odesys - pointer to the ODE system to integrate *
|
||||
* dt - size of the timestep *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* state vector in odesys will be updated for the next timestep *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
* 6/25/99 GTH : Converted to the new Integrator system *
|
||||
*=============================================================================================*/
|
||||
void IntegrationSystem::Runge_Kutta5_Integrate(ODESystemClass * odesys,float dt)
|
||||
{
|
||||
int i;
|
||||
int veclen;
|
||||
static const float a2 = 0.2f;
|
||||
static const float a3 = 0.3f;
|
||||
static const float a4 = 0.6f;
|
||||
static const float a5 = 1.0f;
|
||||
static const float a6 = 0.875f;
|
||||
static const float b21 = 0.2f;
|
||||
static const float b31 = 3.0f/40.0f;
|
||||
static const float b32 = 9.0f/40.0f;
|
||||
static const float b41 = 0.3f;
|
||||
static const float b42 = -0.9f;
|
||||
static const float b43 = 1.2f;
|
||||
static const float b51 = -11.0f /54.0f;
|
||||
static const float b52 = 2.5f;
|
||||
static const float b53 = -70.0f/27.0f;
|
||||
static const float b54 = 35.0f/27.0f;
|
||||
static const float b61 = 1631.0f/55296.0f;
|
||||
static const float b62 = 175.0f/512.0f;
|
||||
static const float b63 = 575.0f/13824.0f;
|
||||
static const float b64 = 44275.0f/110592.0f;
|
||||
static const float b65 = 253.0f/4096.0f;
|
||||
static const float c1 = 37.0f/378.0f;
|
||||
static const float c3 = 250.0f/621.0f;
|
||||
static const float c4 = 125.0f/594.0f;
|
||||
static const float c6 = 512.0f/1771.0f;
|
||||
static const float dc5 = -277.0f/14336.0f;
|
||||
static const float dc1 = c1 - 2825.0f/27648.0f;
|
||||
static const float dc3 = c3 - 18575.0f/48384.0f;
|
||||
static const float dc4 = c4 - 13525.0f/55296.0f;
|
||||
static const float dc6 = c6 - 0.25f;
|
||||
|
||||
/*
|
||||
** Get the current state
|
||||
*/
|
||||
Y0.Reset();
|
||||
odesys->Get_State(Y0);
|
||||
veclen = Y0.Count();
|
||||
Y1.Resize(veclen);
|
||||
|
||||
/*
|
||||
** make aliases to the work-vectors we need
|
||||
*/
|
||||
StateVectorClass & dydt = _WorkVector0;
|
||||
StateVectorClass & ak2 = _WorkVector1;
|
||||
StateVectorClass & ak3 = _WorkVector2;
|
||||
StateVectorClass & ak4 = _WorkVector3;
|
||||
StateVectorClass & ak5 = _WorkVector4;
|
||||
StateVectorClass & ak6 = _WorkVector5;
|
||||
StateVectorClass & ytmp = _WorkVector6;
|
||||
StateVectorClass & yerr = _WorkVector7;
|
||||
|
||||
dydt.Resize(veclen);
|
||||
ak2.Resize(veclen);
|
||||
ak3.Resize(veclen);
|
||||
ak4.Resize(veclen);
|
||||
ak5.Resize(veclen);
|
||||
ak6.Resize(veclen);
|
||||
ytmp.Resize(veclen);
|
||||
yerr.Resize(veclen);
|
||||
|
||||
// First step
|
||||
odesys->Compute_Derivatives(0.0f,NULL,&dydt);
|
||||
for (i=0;i<veclen;i++) {
|
||||
ytmp[i] = Y0[i] + b21*dt*dydt[i];
|
||||
}
|
||||
|
||||
// Second step
|
||||
odesys->Compute_Derivatives(a2*dt, &ytmp, &ak2);
|
||||
for (i=0; i<veclen; i++) {
|
||||
ytmp[i] = Y0[i] + dt*(b31*dydt[i] + b32*ak2[i]);
|
||||
}
|
||||
|
||||
// Third step
|
||||
odesys->Compute_Derivatives(a3*dt, &ytmp, &ak3);
|
||||
for (i=0; i<veclen; i++) {
|
||||
ytmp[i] = Y0[i] + dt*(b41*dydt[i] + b42*ak2[i] + b43*ak3[i]);
|
||||
}
|
||||
|
||||
// Fourth step
|
||||
odesys->Compute_Derivatives(a4*dt, &ytmp, &ak4);
|
||||
for (i=0; i<veclen; i++) {
|
||||
ytmp[i] = Y0[i] + dt*(b51*dydt[i] + b52*ak2[i] + b53*ak3[i] + b54*ak4[i]);
|
||||
}
|
||||
|
||||
// Fifth step
|
||||
odesys->Compute_Derivatives(a5*dt, &ytmp, &ak5);
|
||||
for (i=0; i<veclen; i++) {
|
||||
ytmp[i] = Y0[i] + dt*(b61*dydt[i] + b62*ak2[i] + b63*ak3[i] + b64*ak4[i] + b65*ak5[i]);
|
||||
}
|
||||
|
||||
// Sixth step
|
||||
odesys->Compute_Derivatives(a6*dt, &ytmp, &ak6);
|
||||
for (i=0; i<veclen; i++) {
|
||||
Y1[i] = Y0[i] + dt*(c1*dydt[i] + c3*ak3[i] + c4*ak4[i] + c6*ak6[i]);
|
||||
}
|
||||
|
||||
// Error approximation!
|
||||
// (maybe I should use this someday? nah not going to use this integrator anyway...)
|
||||
for (i=0; i<veclen; i++) {
|
||||
yerr[i] = dt*(dc1*dydt[i] + dc3*ak3[i] + dc4*ak4[i] + dc5*ak5[i] + dc6*ak6[i]);
|
||||
}
|
||||
|
||||
odesys->Set_State(Y1);
|
||||
}
|
||||
|
||||
134
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/ode.h
Normal file
134
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/ode.h
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /G/wwmath/ode.h 9 9/21/99 5:54p Neal_k $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Commando *
|
||||
* *
|
||||
* $Archive:: /G/wwmath/ode.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 9/21/99 5:54p $*
|
||||
* *
|
||||
* $Revision:: 9 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef ODE_H
|
||||
#define ODE_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector.h"
|
||||
#include "wwdebug.h"
|
||||
|
||||
|
||||
/*
|
||||
** StateVectorClass
|
||||
** The state vector for a system of ordinary differential equations will be
|
||||
** stored in this form. It is a dynamically resizeable array so that we don't
|
||||
** have to hard-code a maximum size. If needed, in the final product, we could
|
||||
** do a slight optimization which makes this a normal fixed size array that
|
||||
** we've determined is "big enough".
|
||||
*/
|
||||
class StateVectorClass : public DynamicVectorClass<float>
|
||||
{
|
||||
public:
|
||||
void Reset(void) { ActiveCount = 0; }
|
||||
void Resize(int size) { if (size > VectorMax) { DynamicVectorClass<float>::Resize(size); } }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** ODESystemClass
|
||||
** If a system of Ordinary Differential Equations (ODE's) are put behind an interface
|
||||
** of this type, they can be integrated using the Integrators defined in this module.
|
||||
*/
|
||||
class ODESystemClass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/*
|
||||
** Get_Current_State
|
||||
** This function should fill the given state vector with the
|
||||
** current state of this object. Each state variable should be
|
||||
** inserted into the vector using its 'Add' interface.
|
||||
*/
|
||||
virtual void Get_State(StateVectorClass & set_state) = 0;
|
||||
|
||||
/*
|
||||
** Set_Current_State
|
||||
** This function should read its state from this state vector starting from the
|
||||
** given index. The return value should be the index that the next object should
|
||||
** read from (i.e. increment the index past your state)
|
||||
*/
|
||||
virtual int Set_State(const StateVectorClass & new_state,int start_index = 0) = 0;
|
||||
|
||||
/*
|
||||
** Compute_Derivatives
|
||||
** The various ODE solvers will use this interface to ask the ODESystemClass to
|
||||
** compute the derivatives of their state. In some cases, the integrator will
|
||||
** pass in a new state vector (test_state) to be used when computing the derivatives.
|
||||
** NULL will be passed if they want the derivatives for the initial state.
|
||||
** This function works similarly to the Set_State function in that it passes you
|
||||
** the index to start reading from and you pass it back the index to continue from.
|
||||
*/
|
||||
virtual int Compute_Derivatives(float t,StateVectorClass * test_state,StateVectorClass * dydt,int start_index = 0) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** IntegrationSystem
|
||||
**
|
||||
** The Euler_Solve is the simplest but most inaccurate. It requires only
|
||||
** a single computation of the derivatives per timestep.
|
||||
**
|
||||
** The Midpoint_Solve function will evaluate the derivatives at two points
|
||||
**
|
||||
** The Runge_Kutta_Solve requires four evaluations of the derivatives.
|
||||
** This is the fourth order Runge-Kutta method...
|
||||
**
|
||||
** Runge_Kutta5_Solve is an implementation of fifth order Runge-
|
||||
** Kutta. It requires six evaluations of the derivatives.
|
||||
*/
|
||||
|
||||
class IntegrationSystem
|
||||
{
|
||||
public:
|
||||
|
||||
static void Euler_Integrate(ODESystemClass * sys,float dt);
|
||||
static void Midpoint_Integrate(ODESystemClass * sys,float dt);
|
||||
static void Runge_Kutta_Integrate(ODESystemClass * sys,float dt);
|
||||
static void Runge_Kutta5_Integrate(ODESystemClass * odesys,float dt);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
250
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/plane.h
Normal file
250
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/plane.h
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/plane.h 16 5/05/01 5:48p Jani_p $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Voxel Technology *
|
||||
* *
|
||||
* File Name : PLANE.H *
|
||||
* *
|
||||
* Programmer : Greg Hjelstrom *
|
||||
* *
|
||||
* Start Date : 03/17/97 *
|
||||
* *
|
||||
* Last Update : March 17, 1997 [GH] *
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef PLANE_H
|
||||
#define PLANE_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector3.h"
|
||||
#include "sphere.h"
|
||||
|
||||
/*
|
||||
** PlaneClass
|
||||
**
|
||||
** 3D-planes. This class uses the Normal+Distance description of a plane.
|
||||
** The relationship for all points (p) on the plane is given by:
|
||||
**
|
||||
** N.X * p.X + N.Y * p.Y + N.Z * p.Z = D
|
||||
**
|
||||
** BEWARE, if you are used to the Ax + By + Cz + D = 0 description, the
|
||||
** sign of the D value is inverted.
|
||||
*/
|
||||
|
||||
class PlaneClass
|
||||
{
|
||||
public:
|
||||
|
||||
enum { FRONT = 0, BACK, ON };
|
||||
|
||||
Vector3 N; // Normal of the plane
|
||||
float D; // Distance along the normal from the origin
|
||||
|
||||
PlaneClass(void) : N(0.0f,0.0f,1.0f), D(0.0f) { }
|
||||
|
||||
/*
|
||||
** Plane initialization:
|
||||
** a,b,c,d - explicitly set the four coefficients (note the sign of d!)
|
||||
** normal,dist - explicitly set the normal and distance
|
||||
** normal,point - compute plane with normal, containing point
|
||||
** p1,p2,p3 - compute plane containing three points
|
||||
*/
|
||||
PlaneClass(float nx,float ny,float nz,float dist);
|
||||
PlaneClass(const Vector3 & normal,float dist);
|
||||
PlaneClass(const Vector3 & normal,const Vector3 & point);
|
||||
PlaneClass(const Vector3 & point1,const Vector3 & point2,const Vector3 & point3);
|
||||
|
||||
inline void Set(float a,float b,float c,float d);
|
||||
inline void Set(const Vector3 & normal,float dist);
|
||||
inline void Set(const Vector3 & normal,const Vector3 & point);
|
||||
inline void Set(const Vector3 & point1,const Vector3 & point2,const Vector3 & point3);
|
||||
|
||||
bool Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const;
|
||||
bool In_Front(const Vector3 & point) const;
|
||||
bool In_Front(const SphereClass & sphere) const;
|
||||
bool In_Front_Or_Intersecting(const SphereClass & sphere) const;
|
||||
|
||||
static void Intersect_Planes(const PlaneClass & a, const PlaneClass & b, Vector3 *line_dir, Vector3 *line_point);
|
||||
};
|
||||
|
||||
inline PlaneClass::PlaneClass(float nx,float ny,float nz,float dist)
|
||||
{
|
||||
Set(nx,ny,nz,dist);
|
||||
}
|
||||
|
||||
inline PlaneClass::PlaneClass(const Vector3 & normal,float dist)
|
||||
{
|
||||
Set(normal,dist);
|
||||
}
|
||||
|
||||
inline PlaneClass::PlaneClass(const Vector3 & normal,const Vector3 & point)
|
||||
{
|
||||
Set(normal,point);
|
||||
}
|
||||
|
||||
inline PlaneClass::PlaneClass(const Vector3 & point1, const Vector3 & point2, const Vector3 & point3)
|
||||
{
|
||||
Set(point1,point2,point3);
|
||||
}
|
||||
|
||||
inline void PlaneClass::Set(float a,float b,float c,float d)
|
||||
{
|
||||
N.X = a;
|
||||
N.Y = b;
|
||||
N.Z = c;
|
||||
D = d;
|
||||
}
|
||||
|
||||
inline void PlaneClass::Set(const Vector3 & normal,float dist)
|
||||
{
|
||||
N = normal;
|
||||
D = dist;
|
||||
}
|
||||
|
||||
inline void PlaneClass::Set(const Vector3 & normal,const Vector3 & point)
|
||||
{
|
||||
N = normal;
|
||||
D = Vector3::Dot_Product(normal , point);
|
||||
}
|
||||
|
||||
|
||||
inline void PlaneClass::Set(const Vector3 & point1, const Vector3 & point2, const Vector3 & point3)
|
||||
{
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
N = Vector3::Cross_Product((point2 - point1), (point3 - point1));
|
||||
#else
|
||||
Vector3::Cross_Product((point2 - point1), (point3 - point1), &N);
|
||||
#endif
|
||||
if (N != Vector3(0.0f, 0.0f, 0.0f)) {
|
||||
// Points are not colinear. Normalize N and calculate D.
|
||||
N.Normalize();
|
||||
D = Vector3::Dot_Product(N, point1);
|
||||
} else {
|
||||
// They are colinear - return default plane (constructors can't fail).
|
||||
N = Vector3(0.0f, 0.0f, 1.0f);
|
||||
D = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool PlaneClass::Compute_Intersection(const Vector3 & p0,const Vector3 & p1,float * set_t) const
|
||||
{
|
||||
float num,den;
|
||||
den = Vector3::Dot_Product(N,p1-p0);
|
||||
|
||||
/*
|
||||
** If the denominator is zero, the ray is parallel to the plane
|
||||
*/
|
||||
if (den == 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
num = -(Vector3::Dot_Product(N,p0) - D);
|
||||
|
||||
*set_t = num/den;
|
||||
|
||||
/*
|
||||
** If t is not between 0 and 1, the line containing the segment intersects
|
||||
** the plane but the segment does not
|
||||
*/
|
||||
if ((*set_t < 0.0f) || (*set_t > 1.0f)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool PlaneClass::In_Front(const Vector3 & point) const
|
||||
{
|
||||
float dist = Vector3::Dot_Product(point,N);
|
||||
return (dist > D);
|
||||
}
|
||||
|
||||
// This function returns true if the sphere is in front of the plane.
|
||||
inline bool PlaneClass::In_Front(const SphereClass & sphere) const
|
||||
{
|
||||
float dist = Vector3::Dot_Product(sphere.Center,N);
|
||||
return ((dist - D) >= sphere.Radius);
|
||||
}
|
||||
|
||||
// This function will return 1 if any part of the sphere is in front of the plane.
|
||||
// (i.e. if the sphere is entirely in front of the plane or if it intersects the plane).
|
||||
inline bool PlaneClass::In_Front_Or_Intersecting(const SphereClass & sphere) const
|
||||
{
|
||||
float dist = Vector3::Dot_Product(sphere.Center , N);
|
||||
return ((D - dist) < sphere.Radius);
|
||||
}
|
||||
|
||||
inline void PlaneClass::Intersect_Planes(const PlaneClass & a, const PlaneClass & b, Vector3 *line_dir, Vector3 *line_point)
|
||||
{
|
||||
// Method used is from "plane-to-plane intersection", Graphics Gems III, pp. 233-235.
|
||||
|
||||
// Find line of intersection. First find direction vector of line:
|
||||
Vector3::Cross_Product(a.N, b.N, line_dir);
|
||||
|
||||
// Now find point on line. How we do it depends on what the largest coordinate of the
|
||||
// direction vector is.
|
||||
Vector3 abs_dir = *line_dir;
|
||||
abs_dir.Update_Max(-abs_dir);
|
||||
if (abs_dir.X > abs_dir.Y) {
|
||||
if (abs_dir.X > abs_dir.Z) {
|
||||
// X largest
|
||||
float ool = 1.0f / line_dir->X;
|
||||
line_point->Y = (b.N.Z * a.D - a.N.Z * b.D) * ool;
|
||||
line_point->Z = (a.N.Y * b.D - b.N.Y * a.D) * ool;
|
||||
line_point->X = 0.0f;
|
||||
} else {
|
||||
// Z largest
|
||||
float ool = 1.0f / line_dir->Z;
|
||||
line_point->X = (b.N.Y * a.D - a.N.Y * b.D) * ool;
|
||||
line_point->Y = (a.N.X * b.D - b.N.X * a.D) * ool;
|
||||
line_point->Z = 0.0f;
|
||||
}
|
||||
} else {
|
||||
if (abs_dir.Y > abs_dir.Z) {
|
||||
// Y largest
|
||||
float ool = 1.0f / line_dir->Y;
|
||||
line_point->Z = (b.N.X * a.D - a.N.X * b.D) * ool;
|
||||
line_point->X = (a.N.Z * b.D - b.N.Z * a.D) * ool;
|
||||
line_point->Y = 0.0f;
|
||||
} else {
|
||||
// Z largest
|
||||
float ool = 1.0f / line_dir->Z;
|
||||
line_point->X = (b.N.Y * a.D - a.N.Y * b.D) * ool;
|
||||
line_point->Y = (a.N.X * b.D - b.N.X * a.D) * ool;
|
||||
line_point->Z = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize direction vector (we do it here because we needed the non-normalized version to
|
||||
// find the point).
|
||||
line_dir->Normalize();
|
||||
}
|
||||
|
||||
#endif /*PLANE_H*/
|
||||
118
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/pot.cpp
Normal file
118
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/pot.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 : G *
|
||||
* *
|
||||
* $Archive:: /G/ww3d/POT.CPP $*
|
||||
* *
|
||||
* $Author:: Naty_h $*
|
||||
* *
|
||||
* $Modtime:: 12/23/98 7:58a $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Find_POT -- finds closest inclusive power of 2 to a value *
|
||||
* Find_POT_Log2 -- finds log2 of closest inclusive power of 2 to a value*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "pot.h"
|
||||
|
||||
/**************************************************************************
|
||||
* Find_POT -- finds closest inclusive power of 2 to a value *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/20/1997 PWG : Created. *
|
||||
*========================================================================*/
|
||||
int Find_POT(int val)
|
||||
{
|
||||
// clear out the recorded position and the recorded count
|
||||
int recpos = 0;
|
||||
int reccnt = 0;
|
||||
|
||||
// walk through the value shifting off bits and record the
|
||||
// position of the highest bit, and whether we have found
|
||||
// more than one bit.
|
||||
for (int lp = 0; val; lp++) {
|
||||
if (val & 1) {
|
||||
recpos = lp;
|
||||
reccnt++;
|
||||
}
|
||||
val >>= 1;
|
||||
}
|
||||
// if we have not found more than one bit then the number
|
||||
// was the power of two so return it.
|
||||
if (reccnt < 2) {
|
||||
return( 1 << recpos);
|
||||
}
|
||||
// if we found more than one bit, then the number needs to
|
||||
// be rounded up to the next highest power of 2.
|
||||
return( 1 << (recpos + 1));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Find_POT_Log2 -- finds log2 of closest inclusive power of 2 to a value *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/23/1998 NH : Created. *
|
||||
*========================================================================*/
|
||||
unsigned int Find_POT_Log2(unsigned int val)
|
||||
{
|
||||
// clear out the recorded position and the recorded count
|
||||
int recpos = 0;
|
||||
int reccnt = 0;
|
||||
|
||||
// walk through the value shifting off bits and record the
|
||||
// position of the highest bit, and whether we have found
|
||||
// more than one bit.
|
||||
for (int lp = 0; val; lp++) {
|
||||
if (val & 1) {
|
||||
recpos = lp;
|
||||
reccnt++;
|
||||
}
|
||||
val >>= 1;
|
||||
}
|
||||
// if we have not found more than one bit then the number
|
||||
// was the power of two so return it.
|
||||
if (reccnt < 2) {
|
||||
return recpos;
|
||||
}
|
||||
// if we found more than one bit, then the number needs to
|
||||
// be rounded up to the next highest power of 2.
|
||||
return recpos + 1;
|
||||
}
|
||||
|
||||
|
||||
45
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/pot.h
Normal file
45
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/pot.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 : G *
|
||||
* *
|
||||
* $Archive:: /G/ww3d/POT.H $*
|
||||
* *
|
||||
* $Author:: Naty_h $*
|
||||
* *
|
||||
* $Modtime:: 12/23/98 7:51a $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef __POT_H__
|
||||
#define __POT_H__
|
||||
int Find_POT(int val);
|
||||
unsigned int Find_POT_Log2(unsigned int val);
|
||||
#endif
|
||||
895
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/quat.cpp
Normal file
895
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/quat.cpp
Normal file
@@ -0,0 +1,895 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/quat.cpp 38 8/28/01 10:26a Greg_h $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Voxel Technology *
|
||||
* *
|
||||
* File Name : QUAT.CPP *
|
||||
* *
|
||||
* Programmer : Greg Hjelstrom *
|
||||
* *
|
||||
* Start Date : 02/24/97 *
|
||||
* *
|
||||
* Last Update : February 28, 1997 [GH] *
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Quaternion::Quaternion -- constructor *
|
||||
* Quaternion::Set -- Set the quaternion *
|
||||
* Quaternion::operator= -- Assignment operator *
|
||||
* Quaternion::Make_Closest -- Use nearest representation to the given quaternion. *
|
||||
* Trackball -- Computes a "trackball" quaternion given 2D mouse coordinates *
|
||||
* Axis_To_Quat -- Creates a quaternion given an axis and angle of rotation *
|
||||
* Slerp -- Spherical Linear interpolation! *
|
||||
* Build_Quaternion -- Creates a quaternion from a Matrix *
|
||||
* Build_Matrix -- Creates a Matrix from a Quaternion *
|
||||
* Normalize -- normalizes a quaternion *
|
||||
* Quaternion::Quaternion -- constructor *
|
||||
* Slerp_Setup -- Get ready to call "Cached_Slerp" *
|
||||
* Cached_Slerp -- Quaternion slerping, optimized with cached values *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "quat.h"
|
||||
#include "matrix3d.h"
|
||||
#include "matrix4.h"
|
||||
#include "wwmath.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define SLERP_EPSILON 0.001
|
||||
|
||||
static int _nxt[3] = { 1 , 2 , 0 };
|
||||
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// local functions
|
||||
// ------------------------------------------------------------
|
||||
static float project_to_sphere(float,float,float);
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Quaternion::Quaternion -- constructor *
|
||||
* *
|
||||
* constructs a quaternion from the given axis and angle of rotation (in RADIANS of course) *
|
||||
* *
|
||||
* INPUT: *
|
||||
* axis - axis of the rotation *
|
||||
* angle - rotation angle *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 12/10/97 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
Quaternion::Quaternion(const Vector3 & axis,float angle)
|
||||
{
|
||||
float s = WWMath::Sin(angle/2);
|
||||
float c = WWMath::Cos(angle/2);
|
||||
X = s * axis.X;
|
||||
Y = s * axis.Y;
|
||||
Z = s * axis.Z;
|
||||
W = c;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Quaternion::Normalize -- Normalize to a unit quaternion *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
void Quaternion::Normalize()
|
||||
{
|
||||
float len2=X * X + Y * Y + Z * Z + W * W;
|
||||
if (0.0f == len2) {
|
||||
return;
|
||||
} else {
|
||||
float inv_mag = WWMath::Inv_Sqrt(len2);
|
||||
|
||||
X *= inv_mag;
|
||||
Y *= inv_mag;
|
||||
Z *= inv_mag;
|
||||
W *= inv_mag;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Q::Make_Closest -- Use nearest representation to the given quaternion. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/28/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
Quaternion & Quaternion::Make_Closest(const Quaternion & qto)
|
||||
{
|
||||
float cos_t = qto.X * X + qto.Y * Y + qto.Z * Z + qto.W * W;
|
||||
|
||||
// if we are on opposite hemisphere from qto, negate ourselves
|
||||
if (cos_t < 0.0) {
|
||||
X = -X;
|
||||
Y = -Y;
|
||||
Z = -Z;
|
||||
W = -W;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Trackball -- Computes a "trackball" quaternion given 2D mouse coordinates *
|
||||
* *
|
||||
* INPUT: *
|
||||
* x0,y0 - x1,y1 - "normalized" mouse coordinates for the mouse movement *
|
||||
* sphsize - size of the trackball sphere *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* a quaternion representing the rotation of a trackball *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/28/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
Quaternion Trackball(float x0, float y0, float x1, float y1, float sphsize)
|
||||
{
|
||||
Vector3 a;
|
||||
Vector3 p1;
|
||||
Vector3 p2;
|
||||
Vector3 d;
|
||||
|
||||
float phi,t;
|
||||
|
||||
if ((x0 == x1) && (y0 == y1)) {
|
||||
return Quaternion(0.0f, 0.0f, 0.0f, 1.0f); // Zero rotation
|
||||
}
|
||||
|
||||
|
||||
// Compute z coordinates for projection of p1 and p2 to
|
||||
// deformed sphere
|
||||
p1[0] = x0;
|
||||
p1[1] = y0;
|
||||
p1[2] = project_to_sphere(sphsize, x0, y0);
|
||||
|
||||
p2[0] = x1;
|
||||
p2[1] = y1;
|
||||
p2[2] = project_to_sphere(sphsize, x1, y1);
|
||||
|
||||
|
||||
// Find their cross product
|
||||
Vector3::Cross_Product(p2,p1,&a);
|
||||
|
||||
// Compute how much to rotate
|
||||
d = p1 - p2;
|
||||
t = d.Length() / (2.0f * sphsize);
|
||||
|
||||
// Avoid problems with out of control values
|
||||
if (t > 1.0f) t = 1.0f;
|
||||
if (t < -1.0f) t = -1.0f;
|
||||
phi = 2.0f * WWMath::Asin(t);
|
||||
|
||||
return Axis_To_Quat(a, phi);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Axis_To_Quat -- Creates a quaternion given an axis and angle of rotation *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/28/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
Quaternion Axis_To_Quat(const Vector3 &a, float phi)
|
||||
{
|
||||
Quaternion q;
|
||||
Vector3 tmp = a;
|
||||
|
||||
tmp.Normalize();
|
||||
q[0] = tmp[0];
|
||||
q[1] = tmp[1];
|
||||
q[2] = tmp[2];
|
||||
|
||||
q.Scale(WWMath::Sin(phi / 2.0f));
|
||||
q[3] = WWMath::Cos(phi / 2.0f);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Slerp -- Spherical Linear interpolation! *
|
||||
* *
|
||||
* INPUT: *
|
||||
* p - start quaternion *
|
||||
* q - end quaternion *
|
||||
* alpha - interpolating parameter *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/28/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
|
||||
#if 0
|
||||
#pragma warning (disable : 4725)
|
||||
|
||||
#define ARC_TABLE_SIZE_MASK 1023
|
||||
#define SIN_TABLE_SIZE_MASK 1023
|
||||
|
||||
void __cdecl Fast_Slerp(Quaternion& res, const Quaternion & p,const Quaternion & q,float alpha)
|
||||
{
|
||||
float float_epsilon2=WWMATH_EPSILON * WWMATH_EPSILON;
|
||||
float HalfOfArcTableSize=float(ARC_TABLE_SIZE/2);
|
||||
float HalfOfSinTableSize=float(SIN_TABLE_SIZE/2);
|
||||
const unsigned ARC_TABLE_SIZE_PER_2=ARC_TABLE_SIZE/2;
|
||||
|
||||
float beta; // complementary interploation parameter
|
||||
float theta; // angle between p and q
|
||||
|
||||
__asm {
|
||||
mov esi, p
|
||||
mov edi, q
|
||||
fld1 // we'll need 1.0 and 0.0 later
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// cos theta = dot product of p and q
|
||||
// cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
|
||||
// if q is on opposite hemisphere from A, use -B instead
|
||||
// if (cos_t < 0.0) {
|
||||
// cos_t = -cos_t;
|
||||
// qflip = true;
|
||||
// }
|
||||
// else {
|
||||
// qflip = false;
|
||||
// }
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
fld dword ptr [esi] // p.X
|
||||
fmul dword ptr [edi] // p.X*q.X
|
||||
fld dword ptr [esi+08h] // p.Y
|
||||
fmul dword ptr [edi+08h] // p.Y*q.Y
|
||||
fld dword ptr [esi+04h] // p.Z
|
||||
fmul dword ptr [edi+04h] // p.Z*q.Z
|
||||
fld dword ptr [edi+0ch] // p.W
|
||||
fmul dword ptr [esi+0ch] // p.W*q.W
|
||||
faddp st(2), st(0) // y+=w
|
||||
faddp st(2), st(0) // x+=z
|
||||
faddp st(1),st(0) // x+z + y+w
|
||||
fst beta
|
||||
fabs
|
||||
mov ebx,beta
|
||||
and ebx,0x80000000
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// if q is very close to p, just linearly interpolate
|
||||
// between the two.
|
||||
// if (1.0 - cos_t < WWMATH_EPSILON * WWMATH_EPSILON) {
|
||||
// beta = 1.0 - alpha;
|
||||
// }
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
fld st(0) // duplicate st(0), which contains cos_t
|
||||
fsubr st(0),st(2) // st(2) contains 1.0
|
||||
fcomp float_epsilon2
|
||||
fnstsw ax
|
||||
test ah, 01h
|
||||
je normal_slerp
|
||||
|
||||
fld alpha
|
||||
fsubr st(0),st(1) // st(1) contains 1.0
|
||||
fstp beta
|
||||
jmp done_slerp
|
||||
|
||||
normal_slerp:
|
||||
// ----------------------------------------------------------------------------
|
||||
// normal slerp!
|
||||
// else {
|
||||
// theta = WWMath::Acos(cos_t);
|
||||
// sin_t = WWMath::Sin(theta);
|
||||
// oo_sin_t = 1.0 / sin_t;
|
||||
// beta = WWMath::Sin(theta - alpha*theta) * oo_sin_t;
|
||||
// alpha = WWMath::Sin(alpha*theta) * oo_sin_t;
|
||||
// }
|
||||
// if (qflip) {
|
||||
// alpha = -alpha;
|
||||
// }
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
fld HalfOfSinTableSize
|
||||
fld HalfOfArcTableSize
|
||||
fmul st(0),st(2) // cos_t * (ARC_TABLE_SIZE/2)
|
||||
fistp theta // convert to integer
|
||||
mov eax,theta
|
||||
add eax,ARC_TABLE_SIZE_PER_2
|
||||
jns no_neg
|
||||
xor eax,eax
|
||||
jmp contin
|
||||
no_neg:
|
||||
cmp eax,ARC_TABLE_SIZE
|
||||
jl contin // Note: Use Setcc/Movcc here!!!
|
||||
mov eax,ARC_TABLE_SIZE_MASK
|
||||
contin:
|
||||
fld dword ptr[_FastAcosTable+eax*4]
|
||||
fst theta
|
||||
|
||||
fmul st(0),st(1) // theta * (sin_table_size/2)
|
||||
fadd st(0),st(1) // theta * (sin_table_size/2) + (sin_table_size/2)
|
||||
fistp beta // conver to integer
|
||||
mov ecx,SIN_TABLE_SIZE_MASK
|
||||
mov eax,beta
|
||||
and eax,ecx // & SIN_TABLE_SIZE_MASK
|
||||
fld dword ptr[_FastInvSinTable+eax*4] // 1.0f/sin(theta)
|
||||
|
||||
fld theta
|
||||
fmul alpha // theta*alpha
|
||||
fld st(0) // duplicate stack head as we need theta*alpha later
|
||||
fsubr theta // theta-theta*alpha
|
||||
|
||||
fmul st(0),st(3) // (theta-theta*alpha)*HalfOfSinTableSize
|
||||
fadd st(0),st(3) // (theta-theta*alpha)*HalfOfSinTableSize+HalfOfSinTableSize
|
||||
fistp beta // convert to integer
|
||||
mov eax,beta
|
||||
and eax,ecx // & SIN_TABLE_SIZE_MASK
|
||||
fld dword ptr[_FastSinTable+eax*4] // sin(theta-theta*alpha)
|
||||
|
||||
fmul st(0),st(2) // sin(theta-theta*alpha) * oo_sin_t
|
||||
fstp beta
|
||||
|
||||
fmul st(0),st(2) // (theta*alpha)*HalfOfSinTableSize
|
||||
fadd st(0),st(2) // (theta*alpha)*HalfOfSinTableSize+HalfOfSinTableSize
|
||||
fistp theta // convert to integer
|
||||
mov eax,theta
|
||||
and eax,ecx // & SIN_TABLE_SIZE_MASK
|
||||
fld dword ptr[_FastSinTable+eax*4] // sin(theta*alpha)
|
||||
|
||||
fmul st(0),st(1) // oo_sin_t
|
||||
fstp alpha
|
||||
fstp st(0) // pop oo_sin_t
|
||||
fstp st(0) // pop HalfOfSinTableSize
|
||||
done_slerp:
|
||||
test ebx, ebx
|
||||
je no_negative
|
||||
fld alpha
|
||||
fchs
|
||||
fstp alpha
|
||||
|
||||
no_negative:
|
||||
// ----------------------------------------------------------------------------
|
||||
// res.X = beta*p.X + alpha*q.X;
|
||||
// res.Y = beta*p.Y + alpha*q.Y;
|
||||
// res.Z = beta*p.Z + alpha*q.Z;
|
||||
// res.W = beta*p.W + alpha*q.W;
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
fstp st(0) // pop cos_t
|
||||
fstp st(0) // pop 1.0
|
||||
|
||||
fld alpha
|
||||
fld dword ptr [edi+4] // q.Y
|
||||
fmul st(0),st(1) // alpha*q.Y
|
||||
fld dword ptr [edi+8] // q.Z
|
||||
fmul st(0),st(2) // alpha*q.Z
|
||||
fld dword ptr [edi+12] // q.W
|
||||
fmul st(0),st(3) // alpha*q.W
|
||||
fld dword ptr [edi] // q.X
|
||||
fmulp st(4),st // alpha*q.X
|
||||
|
||||
fld beta
|
||||
fld dword ptr [esi+4] // p.Y
|
||||
fmul st(0),st(1) // beta*p.Y
|
||||
fld dword ptr [esi+8] // p.Z
|
||||
fmul st(0),st(2) // beta*p.Z
|
||||
fld dword ptr [esi] // p.X
|
||||
fmul st(0),st(3) // beta*p.X
|
||||
fxch st(3) // move beta to top of stack
|
||||
fmul dword ptr [esi+12] // beta*p.W
|
||||
|
||||
faddp st(4),st // w
|
||||
faddp st(4),st // z
|
||||
faddp st(4),st // y
|
||||
faddp st(4),st // x
|
||||
|
||||
mov ecx, res
|
||||
fstp [ecx+12] // w
|
||||
fstp [ecx+8] // z
|
||||
fstp [ecx+4] // y
|
||||
fstp [ecx] // x
|
||||
}
|
||||
}
|
||||
#else
|
||||
void __cdecl Fast_Slerp(Quaternion& res, const Quaternion & p,const Quaternion & q,float alpha)
|
||||
{
|
||||
float beta; // complementary interploation parameter
|
||||
float theta; // angle between p and q
|
||||
float cos_t; // sine, cosine of theta
|
||||
float oo_sin_t;
|
||||
int qflip; // use flip of q?
|
||||
|
||||
// cos theta = dot product of p and q
|
||||
cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
|
||||
|
||||
// if q is on opposite hemisphere from A, use -B instead
|
||||
if (cos_t < 0.0f) {
|
||||
cos_t = -cos_t;
|
||||
qflip = true;
|
||||
} else {
|
||||
qflip = false;
|
||||
}
|
||||
|
||||
if (1.0f - cos_t < WWMATH_EPSILON * WWMATH_EPSILON) {
|
||||
|
||||
// if q is very close to p, just linearly interpolate
|
||||
// between the two.
|
||||
beta = 1.0f - alpha;
|
||||
|
||||
} else {
|
||||
|
||||
theta = WWMath::Fast_Acos(cos_t);
|
||||
float sin_t = WWMath::Fast_Sin(theta);
|
||||
oo_sin_t = 1.0f / sin_t;
|
||||
beta = WWMath::Fast_Sin(theta - alpha*theta) * oo_sin_t;
|
||||
alpha = WWMath::Fast_Sin(alpha*theta) * oo_sin_t;
|
||||
}
|
||||
|
||||
if (qflip) {
|
||||
alpha = -alpha;
|
||||
}
|
||||
|
||||
res.X = beta*p.X + alpha*q.X;
|
||||
res.Y = beta*p.Y + alpha*q.Y;
|
||||
res.Z = beta*p.Z + alpha*q.Z;
|
||||
res.W = beta*p.W + alpha*q.W;
|
||||
}
|
||||
|
||||
#endif // MSC_VER
|
||||
|
||||
void Slerp(Quaternion& res, const Quaternion & p,const Quaternion & q,float alpha)
|
||||
{
|
||||
float beta; // complementary interploation parameter
|
||||
float theta; // angle between p and q
|
||||
//float sin_t
|
||||
float cos_t; // sine, cosine of theta
|
||||
float oo_sin_t;
|
||||
int qflip; // use flip of q?
|
||||
|
||||
// cos theta = dot product of p and q
|
||||
cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
|
||||
|
||||
// if q is on opposite hemisphere from A, use -B instead
|
||||
if (cos_t < 0.0f) {
|
||||
cos_t = -cos_t;
|
||||
qflip = true;
|
||||
} else {
|
||||
qflip = false;
|
||||
}
|
||||
|
||||
if (1.0f - cos_t < WWMATH_EPSILON * WWMATH_EPSILON) {
|
||||
|
||||
// if q is very close to p, just linearly interpolate
|
||||
// between the two.
|
||||
beta = 1.0f - alpha;
|
||||
|
||||
} else {
|
||||
|
||||
// normal slerp!
|
||||
theta = WWMath::Acos(cos_t);
|
||||
float sin_t = WWMath::Sin(theta);
|
||||
oo_sin_t = 1.0f / sin_t;
|
||||
beta = WWMath::Sin(theta - alpha*theta) * oo_sin_t;
|
||||
alpha = WWMath::Sin(alpha*theta) * oo_sin_t;
|
||||
}
|
||||
|
||||
if (qflip) {
|
||||
alpha = -alpha;
|
||||
}
|
||||
|
||||
res.X = beta*p.X + alpha*q.X;
|
||||
res.Y = beta*p.Y + alpha*q.Y;
|
||||
res.Z = beta*p.Z + alpha*q.Z;
|
||||
res.W = beta*p.W + alpha*q.W;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Slerp_Setup -- Get ready to call "Cached_Slerp" *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 2/27/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void Slerp_Setup(const Quaternion & p,const Quaternion & q,SlerpInfoStruct * slerpinfo)
|
||||
{
|
||||
float cos_t;
|
||||
|
||||
assert(slerpinfo != NULL);
|
||||
|
||||
// cos theta = dot product of p and q
|
||||
cos_t = p.X * q.X + p.Y * q.Y + p.Z * q.Z + p.W * q.W;
|
||||
|
||||
// if q is on opposite hemisphere from A, use -B instead
|
||||
if (cos_t < 0.0f) {
|
||||
cos_t = -cos_t;
|
||||
slerpinfo->Flip = true;
|
||||
} else {
|
||||
slerpinfo->Flip = false;
|
||||
}
|
||||
|
||||
if (1.0f - cos_t < SLERP_EPSILON) {
|
||||
|
||||
slerpinfo->Linear = true;
|
||||
slerpinfo->Theta = 0.0f;
|
||||
slerpinfo->SinT = 0.0f;
|
||||
|
||||
} else {
|
||||
|
||||
slerpinfo->Linear = false;
|
||||
slerpinfo->Theta = WWMath::Acos(cos_t);
|
||||
slerpinfo->SinT = WWMath::Sin(slerpinfo->Theta);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Cached_Slerp -- Quaternion slerping, optimized with cached values *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 2/27/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
Quaternion Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo)
|
||||
{
|
||||
float beta; // complementary interploation parameter
|
||||
float oo_sin_t;
|
||||
|
||||
if (slerpinfo->Linear) {
|
||||
|
||||
// if q is very close to p, just linearly interpolate
|
||||
// between the two.
|
||||
beta = 1.0f - alpha;
|
||||
|
||||
} else {
|
||||
|
||||
// normal slerp!
|
||||
oo_sin_t = 1.0f / slerpinfo->Theta;
|
||||
beta = WWMath::Sin(slerpinfo->Theta - alpha*slerpinfo->Theta) * oo_sin_t;
|
||||
alpha = WWMath::Sin(alpha*slerpinfo->Theta) * oo_sin_t;
|
||||
}
|
||||
|
||||
if (slerpinfo->Flip) {
|
||||
alpha = -alpha;
|
||||
}
|
||||
|
||||
Quaternion res;
|
||||
res.X = beta*p.X + alpha*q.X;
|
||||
res.Y = beta*p.Y + alpha*q.Y;
|
||||
res.Z = beta*p.Z + alpha*q.Z;
|
||||
res.W = beta*p.W + alpha*q.W;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo,Quaternion * set_q)
|
||||
{
|
||||
float beta; // complementary interploation parameter
|
||||
float oo_sin_t;
|
||||
|
||||
if (slerpinfo->Linear) {
|
||||
|
||||
// if q is very close to p, just linearly interpolate
|
||||
// between the two.
|
||||
beta = 1.0f - alpha;
|
||||
|
||||
} else {
|
||||
|
||||
// normal slerp!
|
||||
oo_sin_t = 1.0f / slerpinfo->Theta;
|
||||
beta = WWMath::Sin(slerpinfo->Theta - alpha*slerpinfo->Theta) * oo_sin_t;
|
||||
alpha = WWMath::Sin(alpha*slerpinfo->Theta) * oo_sin_t;
|
||||
}
|
||||
|
||||
if (slerpinfo->Flip) {
|
||||
alpha = -alpha;
|
||||
}
|
||||
|
||||
set_q->X = beta*p.X + alpha*q.X;
|
||||
set_q->Y = beta*p.Y + alpha*q.Y;
|
||||
set_q->Z = beta*p.Z + alpha*q.Z;
|
||||
set_q->W = beta*p.W + alpha*q.W;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Build_Quaternion -- Creates a quaternion from a Matrix *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* Matrix MUST NOT have scaling! *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/28/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
Quaternion Build_Quaternion(const Matrix3D & mat)
|
||||
{
|
||||
float tr,s;
|
||||
int i,j,k;
|
||||
Quaternion q;
|
||||
|
||||
// sum the diagonal of the rotation matrix
|
||||
tr = mat[0][0] + mat[1][1] + mat[2][2];
|
||||
|
||||
if (tr > 0.0f) {
|
||||
|
||||
s = sqrt(tr + 1.0);
|
||||
q[3] = s * 0.5;
|
||||
s = 0.5 / s;
|
||||
|
||||
q[0] = (mat[2][1] - mat[1][2]) * s;
|
||||
q[1] = (mat[0][2] - mat[2][0]) * s;
|
||||
q[2] = (mat[1][0] - mat[0][1]) * s;
|
||||
|
||||
} else {
|
||||
|
||||
i=0;
|
||||
if (mat[1][1] > mat[0][0]) i = 1;
|
||||
if (mat[2][2] > mat[i][i]) i = 2;
|
||||
j = _nxt[i];
|
||||
k = _nxt[j];
|
||||
|
||||
s = sqrt((mat[i][i] - (mat[j][j] + mat[k][k])) + 1.0);
|
||||
|
||||
q[i] = s * 0.5;
|
||||
if (s != 0.0) {
|
||||
s = 0.5 / s;
|
||||
}
|
||||
|
||||
q[3] = ( mat[k][j] - mat[j][k] ) * s;
|
||||
q[j] = ( mat[j][i] + mat[i][j] ) * s;
|
||||
q[k] = ( mat[k][i] + mat[i][k] ) * s;
|
||||
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
Quaternion Build_Quaternion(const Matrix3x3 & mat)
|
||||
{
|
||||
float tr,s;
|
||||
int i,j,k;
|
||||
Quaternion q;
|
||||
|
||||
// sum the diagonal of the rotation matrix
|
||||
tr = mat[0][0] + mat[1][1] + mat[2][2];
|
||||
|
||||
if (tr > 0.0) {
|
||||
|
||||
s = sqrt(tr + 1.0);
|
||||
q[3] = s * 0.5;
|
||||
s = 0.5 / s;
|
||||
|
||||
q[0] = (mat[2][1] - mat[1][2]) * s;
|
||||
q[1] = (mat[0][2] - mat[2][0]) * s;
|
||||
q[2] = (mat[1][0] - mat[0][1]) * s;
|
||||
|
||||
} else {
|
||||
|
||||
i = 0;
|
||||
if (mat[1][1] > mat[0][0]) i = 1;
|
||||
if (mat[2][2] > mat[i][i]) i = 2;
|
||||
|
||||
j = _nxt[i];
|
||||
k = _nxt[j];
|
||||
|
||||
s = sqrt( (mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0);
|
||||
|
||||
q[i] = s * 0.5;
|
||||
|
||||
if (s != 0.0) {
|
||||
s = 0.5/s;
|
||||
}
|
||||
|
||||
q[3] = ( mat[k][j] - mat[j][k] ) * s;
|
||||
q[j] = ( mat[j][i] + mat[i][j] ) * s;
|
||||
q[k] = ( mat[k][i] + mat[i][k] ) * s;
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
Quaternion Build_Quaternion(const Matrix4x4 & mat)
|
||||
{
|
||||
float tr,s;
|
||||
int i,j,k;
|
||||
Quaternion q;
|
||||
|
||||
// sum the diagonal of the rotation matrix
|
||||
tr = mat[0][0] + mat[1][1] + mat[2][2];
|
||||
|
||||
if (tr > 0.0) {
|
||||
|
||||
s = sqrt(tr + 1.0);
|
||||
q[3] = s * 0.5;
|
||||
s = 0.5 / s;
|
||||
|
||||
q[0] = (mat[2][1] - mat[1][2]) * s;
|
||||
q[1] = (mat[0][2] - mat[2][0]) * s;
|
||||
q[2] = (mat[1][0] - mat[0][1]) * s;
|
||||
|
||||
} else {
|
||||
|
||||
i = 0;
|
||||
if (mat[1][1] > mat[0][0]) i = 1;
|
||||
if (mat[2][2] > mat[i][i]) i = 2;
|
||||
|
||||
j = _nxt[i];
|
||||
k = _nxt[j];
|
||||
|
||||
s = sqrt( (mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0);
|
||||
|
||||
q[i] = s * 0.5;
|
||||
if (s != 0.0) {
|
||||
s = 0.5/s;
|
||||
}
|
||||
q[3] = ( mat[k][j] - mat[j][k] ) * s;
|
||||
q[j] = ( mat[j][i] + mat[i][j] ) * s;
|
||||
q[k] = ( mat[k][i] + mat[i][k] ) * s;
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Build_Matrix -- Creates a Matrix from a Quaternion *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/28/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
Matrix3x3 Build_Matrix3(const Quaternion & q)
|
||||
{
|
||||
Matrix3x3 m;
|
||||
|
||||
m[0][0] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]));
|
||||
m[0][1] = (float)(2.0 * (q[0] * q[1] - q[2] * q[3]));
|
||||
m[0][2] = (float)(2.0 * (q[2] * q[0] + q[1] * q[3]));
|
||||
|
||||
m[1][0] = (float)(2.0 * (q[0] * q[1] + q[2] * q[3]));
|
||||
m[1][1] = (float)(1.0 - 2.0f * (q[2] * q[2] + q[0] * q[0]));
|
||||
m[1][2] = (float)(2.0 * (q[1] * q[2] - q[0] * q[3]));
|
||||
|
||||
m[2][0] = (float)(2.0 * (q[2] * q[0] - q[1] * q[3]));
|
||||
m[2][1] = (float)(2.0 * (q[1] * q[2] + q[0] * q[3]));
|
||||
m[2][2] =(float)(1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
Matrix4x4 Build_Matrix4(const Quaternion & q)
|
||||
{
|
||||
Matrix4x4 m;
|
||||
|
||||
// initialize the rotation sub-matrix
|
||||
m[0][0] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]));
|
||||
m[0][1] = (float)(2.0 * (q[0] * q[1] - q[2] * q[3]));
|
||||
m[0][2] = (float)(2.0 * (q[2] * q[0] + q[1] * q[3]));
|
||||
|
||||
m[1][0] = (float)(2.0 * (q[0] * q[1] + q[2] * q[3]));
|
||||
m[1][1] = (float)(1.0 - 2.0f * (q[2] * q[2] + q[0] * q[0]));
|
||||
m[1][2] = (float)(2.0 * (q[1] * q[2] - q[0] * q[3]));
|
||||
|
||||
m[2][0] = (float)(2.0 * (q[2] * q[0] - q[1] * q[3]));
|
||||
m[2][1] = (float)(2.0 * (q[1] * q[2] + q[0] * q[3]));
|
||||
m[2][2] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]));
|
||||
|
||||
// no translation
|
||||
m[0][3] = m[1][3] = m[2][3] = 0.0f;
|
||||
|
||||
// last row
|
||||
m[3][0] = m[3][1] = m[3][2] = 0.0f;
|
||||
m[3][3] = 1.0f;
|
||||
return m;
|
||||
}
|
||||
|
||||
void Quaternion::Rotate_X(float theta)
|
||||
{
|
||||
// TODO: optimize this
|
||||
*this = (*this) * Quaternion(Vector3(1,0,0),theta);
|
||||
}
|
||||
|
||||
void Quaternion::Rotate_Y(float theta)
|
||||
{
|
||||
// TODO: optimize this
|
||||
*this = (*this) * Quaternion(Vector3(0,1,0),theta);
|
||||
}
|
||||
|
||||
void Quaternion::Rotate_Z(float theta)
|
||||
{
|
||||
// TODO: optimize this
|
||||
*this = (*this) * Quaternion(Vector3(0,0,1),theta);
|
||||
}
|
||||
|
||||
float project_to_sphere(float r, float x, float y)
|
||||
{
|
||||
const float SQRT2 = 1.41421356f;
|
||||
float t, z;
|
||||
float d = WWMath::Sqrt(x * x + y * y);
|
||||
|
||||
if (d < r * (SQRT2/(2.0f))) // inside sphere
|
||||
z = WWMath::Sqrt(r * r - d * d);
|
||||
else { // on hyperbola
|
||||
t = r / SQRT2;
|
||||
z = t * t / d;
|
||||
}
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
void Quaternion::Randomize(void)
|
||||
{
|
||||
X = ((float) (rand() & 0xFFFF)) / 65536.0f;
|
||||
Y = ((float) (rand() & 0xFFFF)) / 65536.0f;
|
||||
Z = ((float) (rand() & 0xFFFF)) / 65536.0f;
|
||||
W = ((float) (rand() & 0xFFFF)) / 65536.0f;
|
||||
|
||||
Normalize();
|
||||
}
|
||||
|
||||
|
||||
317
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/quat.h
Normal file
317
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/quat.h
Normal file
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/quat.h 29 5/11/01 7:11p Jani_p $ */
|
||||
/***************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***************************************************************************
|
||||
* *
|
||||
* Project Name : Voxel Technology *
|
||||
* *
|
||||
* File Name : QUAT.H *
|
||||
* *
|
||||
* Programmer : Greg Hjelstrom *
|
||||
* *
|
||||
* Start Date : 02/24/97 *
|
||||
* *
|
||||
* Last Update : February 24, 1997 [GH] *
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef QUAT_H
|
||||
#define QUAT_H
|
||||
|
||||
#include "always.h"
|
||||
#include "wwmath.h"
|
||||
#include "matrix3.h"
|
||||
#include "vector3.h"
|
||||
#include "matrix3d.h"
|
||||
|
||||
|
||||
class Quaternion
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
|
||||
// X,Y,Z are the imaginary parts of the quaterion
|
||||
// W is the real part
|
||||
float X;
|
||||
float Y;
|
||||
float Z;
|
||||
float W;
|
||||
|
||||
public:
|
||||
|
||||
WWINLINE Quaternion(void) {};
|
||||
WWINLINE explicit Quaternion(bool init) { if (init) { X = 0.0f; Y = 0.0f; Z = 0.0f; W = 1.0f; } }
|
||||
WWINLINE explicit Quaternion(float a, float b, float c, float d) { X=a; Y=b; Z=c; W=d; }
|
||||
WWINLINE explicit Quaternion(const Vector3 & axis,float angle);
|
||||
WWINLINE Quaternion & operator=(const Quaternion & source);
|
||||
|
||||
WWINLINE void Set(float a = 0.0, float b = 0.0, float c = 0.0, float d = 1.0) { X = a; Y = b; Z = c; W = d; }
|
||||
WWINLINE void Make_Identity(void) { Set(); };
|
||||
WWINLINE void Scale(float s) { X = (float)(s*X); Y = (float)(s*Y); Z = (float)(s*Z); W = (float)(s*W); }
|
||||
|
||||
// Array access
|
||||
WWINLINE float & operator [](int i) { return (&X)[i]; }
|
||||
WWINLINE const float & operator [](int i) const { return (&X)[i]; }
|
||||
|
||||
// Unary operators.
|
||||
// Remember that q and -q represent the same 3D rotation.
|
||||
WWINLINE Quaternion operator-() const { return(Quaternion(-X,-Y,-Z,-W)); }
|
||||
WWINLINE Quaternion operator+() const { return *this; }
|
||||
|
||||
// Every 3D rotation can be expressed by two different quaternions, This
|
||||
// function makes the current quaternion convert itself to the representation
|
||||
// which is closer on the 4D unit-hypersphere to the given quaternion.
|
||||
Quaternion & Make_Closest(const Quaternion & qto);
|
||||
|
||||
// Square of the magnitude of the quaternion
|
||||
WWINLINE float Length2(void) const { return (X*X + Y*Y + Z*Z + W*W); }
|
||||
|
||||
// Magnitude of the quaternion
|
||||
WWINLINE float Length(void) const { return WWMath::Sqrt(Length2()); }
|
||||
|
||||
// Make the quaternion unit length
|
||||
void Normalize(void);
|
||||
|
||||
// post-concatenate rotations about the coordinate axes
|
||||
void Rotate_X(float theta);
|
||||
void Rotate_Y(float theta);
|
||||
void Rotate_Z(float theta);
|
||||
|
||||
// initialize this quaternion randomly (creates a random *unit* quaternion)
|
||||
void Randomize(void);
|
||||
|
||||
// transform (rotate) a vector with this quaternion
|
||||
WWINLINE Vector3 Rotate_Vector(const Vector3 & v) const;
|
||||
WWINLINE void Rotate_Vector(const Vector3 & v,Vector3 * set_result) const;
|
||||
|
||||
// verify that none of the members of this quaternion are invalid floats
|
||||
bool Is_Valid(void) const;
|
||||
};
|
||||
|
||||
// Inverse of the quaternion (1/q)
|
||||
WWINLINE Quaternion Inverse(const Quaternion & a)
|
||||
{
|
||||
return Quaternion(-a[0],-a[1],-a[2],a[3]);
|
||||
}
|
||||
|
||||
// Conjugate of the quaternion
|
||||
WWINLINE Quaternion Conjugate(const Quaternion & a)
|
||||
{
|
||||
return Quaternion(-a[0],-a[1],-a[2],a[3]);
|
||||
}
|
||||
|
||||
// Add two quaternions
|
||||
WWINLINE Quaternion operator + (const Quaternion & a,const Quaternion & b)
|
||||
{
|
||||
return Quaternion(a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]);
|
||||
}
|
||||
|
||||
// Subract two quaternions
|
||||
WWINLINE Quaternion operator - (const Quaternion & a,const Quaternion & b)
|
||||
{
|
||||
return Quaternion(a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]);
|
||||
}
|
||||
|
||||
// Multiply a quaternion by a scalar:
|
||||
WWINLINE Quaternion operator * (float scl, const Quaternion & a)
|
||||
{
|
||||
return Quaternion(scl*a[0], scl*a[1], scl*a[2], scl*a[3]);
|
||||
}
|
||||
|
||||
// Multiply a quaternion by a scalar
|
||||
WWINLINE Quaternion operator * (const Quaternion & a, float scl)
|
||||
{
|
||||
return scl*a;
|
||||
}
|
||||
|
||||
// Multiply two quaternions
|
||||
WWINLINE Quaternion operator * (const Quaternion & a,const Quaternion & b)
|
||||
{
|
||||
return Quaternion
|
||||
(
|
||||
a.W*b.X + b.W*a.X + (a.Y*b.Z - b.Y*a.Z),
|
||||
a.W*b.Y + b.W*a.Y - (a.X*b.Z - b.X*a.Z),
|
||||
a.W*b.Z + b.W*a.Z + (a.X*b.Y - b.X*a.Y),
|
||||
a.W * b.W - (a.X * b.X + a.Y * b.Y + a.Z * b.Z)
|
||||
);
|
||||
}
|
||||
|
||||
// Divide two quaternions
|
||||
WWINLINE Quaternion operator / (const Quaternion & a,const Quaternion & b)
|
||||
{
|
||||
return a * Inverse(b);
|
||||
}
|
||||
|
||||
// Normalized version of the quaternion
|
||||
WWINLINE Quaternion Normalize(const Quaternion & a)
|
||||
{
|
||||
float mag = a.Length();
|
||||
if (0.0f == mag) {
|
||||
return a;
|
||||
} else {
|
||||
float oomag = 1.0f / mag;
|
||||
return Quaternion(a[0] * oomag, a[1] * oomag, a[2] * oomag, a[3] * oomag);
|
||||
}
|
||||
}
|
||||
|
||||
// This function computes a quaternion based on an axis
|
||||
// (defined by the given Vector a) and an angle about
|
||||
// which to rotate. The angle is expressed in radians.
|
||||
Quaternion Axis_To_Quat(const Vector3 &a, float angle);
|
||||
|
||||
// Pass the x and y coordinates of the last and current position
|
||||
// of the mouse, scaled so they are from -1.0 to 1.0
|
||||
// The quaternion is the computed as the rotation of a trackball
|
||||
// between the two points projected onto a sphere. This can
|
||||
// be used to implement an intuitive viewing control system.
|
||||
Quaternion Trackball(float x0, float y0, float x1, float y1, float sphsize);
|
||||
|
||||
// Spherical Linear interpolation of quaternions
|
||||
//Quaternion Slerp(const Quaternion & a,const Quaternion & b,float t);
|
||||
void __cdecl Slerp(Quaternion& result, const Quaternion & a,const Quaternion & b,float t);
|
||||
// Fast slerp is innaccurate but multiple times faster
|
||||
void __cdecl Fast_Slerp(Quaternion& result, const Quaternion & a,const Quaternion & b,float t);
|
||||
|
||||
// Convert a rotation matrix into a quaternion
|
||||
Quaternion Build_Quaternion(const Matrix3x3 & matrix);
|
||||
Quaternion Build_Quaternion(const Matrix3D & matrix);
|
||||
Quaternion Build_Quaternion(const Matrix4x4 & matrix);
|
||||
|
||||
// Convert a quaternion into a rotation matrix
|
||||
Matrix3x3 Build_Matrix3(const Quaternion & quat);
|
||||
Matrix3D &Build_Matrix3D(const Quaternion & q, Matrix3D &out);
|
||||
WWINLINE Matrix3D &Build_Matrix3D(const Quaternion & q, Matrix3D &out)
|
||||
{
|
||||
out[0][0] = (float)(1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]));
|
||||
out[0][1] = (float)(2.0 * (q[0] * q[1] - q[2] * q[3]));
|
||||
out[0][2] = (float)(2.0 * (q[2] * q[0] + q[1] * q[3]));
|
||||
|
||||
out[1][0] = (float)(2.0 * (q[0] * q[1] + q[2] * q[3]));
|
||||
out[1][1] = (float)(1.0 - 2.0f * (q[2] * q[2] + q[0] * q[0]));
|
||||
out[1][2] = (float)(2.0 * (q[1] * q[2] - q[0] * q[3]));
|
||||
|
||||
out[2][0] = (float)(2.0 * (q[2] * q[0] - q[1] * q[3]));
|
||||
out[2][1] = (float)(2.0 * (q[1] * q[2] + q[0] * q[3]));
|
||||
out[2][2] =(float)(1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]));
|
||||
|
||||
// no translation
|
||||
out[0][3] = out[1][3] = out[2][3] = 0.0f;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
Matrix4x4 Build_Matrix4(const Quaternion & quat);
|
||||
|
||||
|
||||
// Some values can be cached if you are performing multiple slerps
|
||||
// between the same two quaternions...
|
||||
struct SlerpInfoStruct
|
||||
{
|
||||
float SinT;
|
||||
float Theta;
|
||||
bool Flip;
|
||||
bool Linear;
|
||||
};
|
||||
|
||||
// Cached slerp implementation
|
||||
void Slerp_Setup(const Quaternion & p,const Quaternion & q,SlerpInfoStruct * slerpinfo);
|
||||
void Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo,Quaternion * set_q);
|
||||
Quaternion Cached_Slerp(const Quaternion & p,const Quaternion & q,float alpha,SlerpInfoStruct * slerpinfo);
|
||||
|
||||
WWINLINE Vector3 Quaternion::Rotate_Vector(const Vector3 & v) const
|
||||
{
|
||||
float x = W*v.X + (Y*v.Z - v.Y*Z);
|
||||
float y = W*v.Y - (X*v.Z - v.X*Z);
|
||||
float z = W*v.Z + (X*v.Y - v.X*Y);
|
||||
float w = -(X*v.X + Y*v.Y + Z*v.Z);
|
||||
|
||||
return Vector3
|
||||
(
|
||||
w*(-X) + W*x + (y*(-Z) - (-Y)*z),
|
||||
w*(-Y) + W*y - (x*(-Z) - (-X)*z),
|
||||
w*(-Z) + W*z + (x*(-Y) - (-X)*y)
|
||||
);
|
||||
}
|
||||
|
||||
WWINLINE void Quaternion::Rotate_Vector(const Vector3 & v,Vector3 * result) const
|
||||
{
|
||||
assert(result != NULL);
|
||||
|
||||
float x = W*v.X + (Y*v.Z - v.Y*Z);
|
||||
float y = W*v.Y - (X*v.Z - v.X*Z);
|
||||
float z = W*v.Z + (X*v.Y - v.X*Y);
|
||||
float w = -(X*v.X + Y*v.Y + Z*v.Z);
|
||||
|
||||
result->X = w*(-X) + W*x + (y*(-Z) - (-Y)*z);
|
||||
result->Y = w*(-Y) + W*y - (x*(-Z) - (-X)*z);
|
||||
result->Z = w*(-Z) + W*z + (x*(-Y) - (-X)*y);
|
||||
}
|
||||
|
||||
WWINLINE bool Quaternion::Is_Valid(void) const
|
||||
{
|
||||
return ( WWMath::Is_Valid_Float(X) &&
|
||||
WWMath::Is_Valid_Float(Y) &&
|
||||
WWMath::Is_Valid_Float(Z) &&
|
||||
WWMath::Is_Valid_Float(W) );
|
||||
}
|
||||
|
||||
WWINLINE bool Equal_Within_Epsilon(const Quaternion &a, const Quaternion &b, float epsilon)
|
||||
{
|
||||
return( (WWMath::Fabs(a.X - b.X) < epsilon) &&
|
||||
(WWMath::Fabs(a.Y - b.Y) < epsilon) &&
|
||||
(WWMath::Fabs(a.Z - b.Z) < epsilon) &&
|
||||
(WWMath::Fabs(a.W - b.W) < epsilon) );
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Quaternion::operator= -- Assignment operator *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Quaternion & Quaternion::operator = (const Quaternion & source)
|
||||
{
|
||||
X = source[0];
|
||||
Y = source[1];
|
||||
Z = source[2];
|
||||
W = source[3];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
#endif /* QUAT_H */
|
||||
|
||||
|
||||
|
||||
108
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/rect.h
Normal file
108
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/rect.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/rect.h $*
|
||||
* *
|
||||
* Author:: Byon Garrabrant *
|
||||
* *
|
||||
* $Modtime:: 4/16/01 10:01a $*
|
||||
* *
|
||||
* $Revision:: 9 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef RECT_H
|
||||
#define RECT_H
|
||||
|
||||
#include "vector2.h"
|
||||
|
||||
class RectClass
|
||||
{
|
||||
public:
|
||||
float Left;
|
||||
float Top;
|
||||
float Right;
|
||||
float Bottom;
|
||||
|
||||
// Constructors
|
||||
RectClass( void ) {};
|
||||
RectClass( const RectClass & r ) { Left = r.Left; Top = r.Top; Right = r.Right; Bottom = r.Bottom; }
|
||||
RectClass( float left, float top, float right, float bottom ) { Left = left; Top = top; Right = right; Bottom = bottom; }
|
||||
RectClass( const Vector2 & top_left, const Vector2 & bottom_right ) { Left = top_left.X; Top = top_left.Y; Right = bottom_right.X; Bottom = bottom_right.Y; }
|
||||
|
||||
// Assignment
|
||||
RectClass & operator = (const RectClass & r) { Left = r.Left; Top = r.Top; Right = r.Right; Bottom = r.Bottom; return *this; }
|
||||
void Set(float left, float top, float right, float bottom) { Left = left; Top = top; Right = right; Bottom = bottom; }
|
||||
void Set( const Vector2 & top_left, const Vector2 & bottom_right ) { Left = top_left.X; Top = top_left.Y; Right = bottom_right.X; Bottom = bottom_right.Y; }
|
||||
void Set(const RectClass & r) { Left = r.Left; Top = r.Top; Right = r.Right; Bottom = r.Bottom; }
|
||||
|
||||
// Access
|
||||
float Width(void) const { return Right - Left; }
|
||||
float Height(void) const { return Bottom - Top; }
|
||||
Vector2 Center( void ) const { return Vector2( (Left + Right)/2, (Top + Bottom)/2 ); }
|
||||
Vector2 Extent( void ) const { return Vector2( (Right - Left)/2, (Bottom - Top)/2 ); }
|
||||
Vector2 Upper_Left( void ) const { return Vector2( Left, Top ); }
|
||||
Vector2 Lower_Right( void ) const { return Vector2( Right, Bottom ); }
|
||||
Vector2 Upper_Right( void ) const { return Vector2( Right, Top ); }
|
||||
Vector2 Lower_Left( void ) const { return Vector2( Left, Bottom ); }
|
||||
|
||||
// Scaling
|
||||
RectClass & operator *= (float k) { return Scale( k ); }
|
||||
RectClass & operator /= (float k) { return Scale( 1/k ); }
|
||||
RectClass & Scale_Relative_Center( float k ) { Vector2 center = Center(); *this-=center; Left*=k; Top*=k; Right*=k; Bottom*=k; *this+=center; return *this; }
|
||||
RectClass & Scale( float k ) { Left*=k; Top*=k; Right*=k; Bottom*=k; return *this; }
|
||||
RectClass & Scale( const Vector2 &k ) { Left*=k.X; Top*=k.Y; Right*=k.X; Bottom*=k.Y; return *this; }
|
||||
RectClass & Inverse_Scale( const Vector2 &k ) { Left/=k.X; Top/=k.Y; Right/=k.X; Bottom/=k.Y; return *this; }
|
||||
|
||||
// Offset
|
||||
RectClass & operator += ( const Vector2 & o ) { Left+=o.X; Top+=o.Y; Right+=o.X; Bottom+=o.Y; return *this; }
|
||||
RectClass & operator -= ( const Vector2 & o ) { Left-=o.X; Top-=o.Y; Right-=o.X; Bottom-=o.Y; return *this; }
|
||||
|
||||
// Inflate
|
||||
void Inflate( const Vector2 & o ) { Left-=o.X; Top-=o.Y; Right+=o.X; Bottom+=o.Y; }
|
||||
|
||||
// Union
|
||||
RectClass & operator += ( const RectClass & r ) { Left=MIN(Left,r.Left); Top=MIN(Top,r.Top); Right=MAX(Right,r.Right); Bottom=MAX(Bottom,r.Bottom); return *this; }
|
||||
|
||||
// Equality
|
||||
bool operator == ( const RectClass &rval ) const { return (rval.Left == Left) && (rval.Right == Right) && (rval.Top == Top) && (rval.Bottom == Bottom); }
|
||||
bool operator != ( const RectClass &rval ) const { return (rval.Left != Left) || (rval.Right != Right) || (rval.Top != Top) || (rval.Bottom != Bottom); }
|
||||
|
||||
// Containment
|
||||
bool Contains ( const Vector2 &pos ) const { return (pos.X >= Left) && (pos.X <= Right) && (pos.Y >= Top) && (pos.Y <= Bottom); }
|
||||
|
||||
// Misc
|
||||
void Snap_To_Units( const Vector2 & u ) { Left = (int)(Left / u.X + 0.5f) * u.X; Right = (int)(Right / u.X + 0.5f) * u.X; Top = (int)(Top / u.Y + 0.5f) * u.Y; Bottom = (int)(Bottom / u.Y + 0.5f) * u.Y; }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
552
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/sphere.h
Normal file
552
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/sphere.h
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/sphere.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 3/29/01 10:37a $*
|
||||
* *
|
||||
* $Revision:: 18 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* SphereClass::SphereClass -- constructor *
|
||||
* SphereClass::Init -- assign a new center and radius to this sphere *
|
||||
* SphereClass::Re_Center -- move the center, update radius to enclose old sphere *
|
||||
* SphereClass::Add_Sphere -- expands 'this' sphere to enclose the given sphere *
|
||||
* SphereClass::Transform -- transforms this sphere *
|
||||
* SphereClass::Volume -- returns the volume of this sphere *
|
||||
* SphereClass::operator+= -- 'Add' a sphere to this one *
|
||||
* SphereClass::operator *= -- transform this sphere by the given radius *
|
||||
* Spheres_Intersect -- test whether two spheres intersect *
|
||||
* Add_Spheres -- Add two spheres together, creating sphere which encloses both *
|
||||
* operator + -- Add two spheres together, creating a sphere which encloses both *
|
||||
* Transform Sphere -- transform a sphere *
|
||||
* Transform_Sphere -- transform a sphere *
|
||||
* operator * -- Transform a sphere *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef SPHERE_H
|
||||
#define SPHERE_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector3.h"
|
||||
#include "matrix3d.h"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// SphereClass
|
||||
//
|
||||
// Center - center of the sphere.
|
||||
// Radius - radius of the sphere
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
class SphereClass
|
||||
{
|
||||
public:
|
||||
inline SphereClass(void) { };
|
||||
inline SphereClass(const Vector3 & center,float radius) { Init(center,radius); }
|
||||
inline SphereClass(const Matrix3D& mtx,const Vector3 & center,float radius) { Init(mtx,center,radius); }
|
||||
inline SphereClass(const Vector3 & center,const SphereClass & s0);
|
||||
inline SphereClass(const Vector3 *Position, const int VertCount);
|
||||
|
||||
inline void Init(const Vector3 & pos,float radius);
|
||||
inline void Init(const Matrix3D& mtx,const Vector3 & pos,float radius);
|
||||
inline void Re_Center(const Vector3 & center);
|
||||
inline void Add_Sphere(const SphereClass & s);
|
||||
inline void Transform(const Matrix3D & tm);
|
||||
inline float Volume(void) const;
|
||||
|
||||
inline SphereClass & operator += (const SphereClass & s);
|
||||
inline SphereClass & operator *= (const Matrix3D & m);
|
||||
|
||||
Vector3 Center;
|
||||
float Radius;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* SphereClass::SphereClass -- constructor *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline SphereClass::SphereClass(const Vector3 & center,const SphereClass & s0)
|
||||
{
|
||||
float dist = (s0.Center - center).Length();
|
||||
Center = center;
|
||||
Radius = s0.Radius + dist;
|
||||
}
|
||||
|
||||
inline SphereClass::SphereClass(const Vector3 *Position,const int VertCount)
|
||||
{
|
||||
int i;
|
||||
double dx,dy,dz;
|
||||
|
||||
// bounding sphere
|
||||
// Using the algorithm described in Graphics Gems I page 301.
|
||||
// This algorithm supposedly generates a bounding sphere within
|
||||
// 5% of the optimal one but is much faster and simpler to implement.
|
||||
Vector3 xmin(Position[0].X,Position[0].Y,Position[0].Z);
|
||||
Vector3 xmax(Position[0].X,Position[0].Y,Position[0].Z);
|
||||
Vector3 ymin(Position[0].X,Position[0].Y,Position[0].Z);
|
||||
Vector3 ymax(Position[0].X,Position[0].Y,Position[0].Z);
|
||||
Vector3 zmin(Position[0].X,Position[0].Y,Position[0].Z);
|
||||
Vector3 zmax(Position[0].X,Position[0].Y,Position[0].Z);
|
||||
|
||||
|
||||
// FIRST PASS:
|
||||
// finding the 6 minima and maxima points
|
||||
for (i=1; i<VertCount; i++) {
|
||||
if (Position[i].X < xmin.X) {
|
||||
xmin.X = Position[i].X; xmin.Y = Position[i].Y; xmin.Z = Position[i].Z;
|
||||
}
|
||||
if (Position[i].X > xmax.X) {
|
||||
xmax.X = Position[i].X; xmax.Y = Position[i].Y; xmax.Z = Position[i].Z;
|
||||
}
|
||||
if (Position[i].Y < ymin.Y) {
|
||||
ymin.X = Position[i].X; ymin.Y = Position[i].Y; ymin.Z = Position[i].Z;
|
||||
}
|
||||
if (Position[i].Y > ymax.Y) {
|
||||
ymax.X = Position[i].X; ymax.Y = Position[i].Y; ymax.Z = Position[i].Z;
|
||||
}
|
||||
if (Position[i].Z < zmin.Z) {
|
||||
zmin.X = Position[i].X; zmin.Y = Position[i].Y; zmin.Z = Position[i].Z;
|
||||
}
|
||||
if (Position[i].Z > zmax.Z) {
|
||||
zmax.X = Position[i].X; zmax.Y = Position[i].Y; zmax.Z = Position[i].Z;
|
||||
}
|
||||
}
|
||||
|
||||
// xspan = distance between the 2 points xmin and xmax squared.
|
||||
// same goes for yspan and zspan.
|
||||
dx = xmax.X - xmin.X;
|
||||
dy = xmax.Y - xmin.Y;
|
||||
dz = xmax.Z - xmin.Z;
|
||||
double xspan = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
dx = ymax.X - ymin.X;
|
||||
dy = ymax.Y - ymin.Y;
|
||||
dz = ymax.Z - ymin.Z;
|
||||
double yspan = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
dx = zmax.X - zmin.X;
|
||||
dy = zmax.Y - zmin.Y;
|
||||
dz = zmax.Z - zmin.Z;
|
||||
double zspan = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
|
||||
// Set points dia1 and dia2 to the maximally separated pair
|
||||
// This will be the diameter of the initial sphere
|
||||
Vector3 dia1 = xmin;
|
||||
Vector3 dia2 = xmax;
|
||||
double maxspan = xspan;
|
||||
|
||||
if (yspan > maxspan) {
|
||||
maxspan = yspan;
|
||||
dia1 = ymin;
|
||||
dia2 = ymax;
|
||||
}
|
||||
if (zspan > maxspan) {
|
||||
maxspan = zspan;
|
||||
dia1 = zmin;
|
||||
dia2 = zmax;
|
||||
}
|
||||
|
||||
|
||||
// Compute initial center and radius and radius squared
|
||||
Vector3 center;
|
||||
center.X = (dia1.X + dia2.X) / 2.0f;
|
||||
center.Y = (dia1.Y + dia2.Y) / 2.0f;
|
||||
center.Z = (dia1.Z + dia2.Z) / 2.0f;
|
||||
|
||||
dx = dia2.X - center.X;
|
||||
dy = dia2.Y - center.Y;
|
||||
dz = dia2.Z - center.Z;
|
||||
|
||||
double radsqr = dx*dx + dy*dy + dz*dz;
|
||||
double radius = sqrt(radsqr);
|
||||
|
||||
|
||||
// SECOND PASS:
|
||||
// Increment current sphere if any points fall outside of it.
|
||||
for (i=0; i<VertCount; i++) {
|
||||
|
||||
dx = Position[i].X - center.X;
|
||||
dy = Position[i].Y - center.Y;
|
||||
dz = Position[i].Z - center.Z;
|
||||
|
||||
double testrad2 = dx*dx + dy*dy + dz*dz;
|
||||
|
||||
if (testrad2 > radsqr) {
|
||||
|
||||
// this point was outside the old sphere, compute a new
|
||||
// center point and radius which contains this point
|
||||
double testrad = sqrt(testrad2);
|
||||
|
||||
// adjust center and radius
|
||||
radius = (radius + testrad) / 2.0;
|
||||
radsqr = radius * radius;
|
||||
|
||||
double oldtonew = testrad - radius;
|
||||
center.X = (radius * center.X + oldtonew * Position[i].X) / testrad;
|
||||
center.Y = (radius * center.Y + oldtonew * Position[i].Y) / testrad;
|
||||
center.Z = (radius * center.Z + oldtonew * Position[i].Z) / testrad;
|
||||
}
|
||||
}
|
||||
|
||||
Center = center;
|
||||
Radius = radius;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* SphereClass::Init -- assign a new center and radius to this sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void SphereClass::Init(const Vector3 & pos,float radius)
|
||||
{
|
||||
Center = pos;
|
||||
Radius = radius;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* SphereClass::Init -- assign a new center and radius to this sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void SphereClass::Init(const Matrix3D& mtx, const Vector3 & pos,float radius)
|
||||
{
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
Center = mtx * pos;
|
||||
#else
|
||||
mtx.mulVector3(pos, Center);
|
||||
#endif
|
||||
Radius = radius;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* SphereClass::Re_Center -- move the center, update radius to enclose old sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void SphereClass::Re_Center(const Vector3 & center)
|
||||
{
|
||||
float dist = (Center - center).Length();
|
||||
Center = center;
|
||||
Radius += dist;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* SphereClass::Add_Sphere -- expands 'this' sphere to enclose the given sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void SphereClass::Add_Sphere(const SphereClass & s)
|
||||
{
|
||||
if (s.Radius == 0.0f) return;
|
||||
|
||||
float dist = (s.Center - Center).Length();
|
||||
if (dist == 0.0f) {
|
||||
Radius = (Radius > s.Radius) ? Radius : s.Radius;
|
||||
return;
|
||||
}
|
||||
|
||||
float rnew = (dist + Radius + s.Radius) / 2.0f;
|
||||
|
||||
// If rnew is smaller than either of the two sphere radii (it can't be
|
||||
// smaller than both of them), this means that the smaller sphere is
|
||||
// completely inside the larger, and the result of adding the two is
|
||||
// simply the larger sphere. If rnew isn't less than either of them, it is
|
||||
// the new radius - calculate the new center.
|
||||
if (rnew < Radius) {
|
||||
// The existing sphere is the result - do nothing.
|
||||
} else {
|
||||
if (rnew < s.Radius) {
|
||||
// The new sphere is the result:
|
||||
Init(s.Center, s.Radius);
|
||||
} else {
|
||||
// Neither sphere is completely inside the other, so rnew is the new
|
||||
// radius - calculate the new center
|
||||
float lerp = (rnew - Radius) / dist;
|
||||
Vector3 center = (s.Center - Center) * lerp + Center;
|
||||
Init(center, rnew);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* SphereClass::Transform -- transforms this sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/12/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void SphereClass::Transform(const Matrix3D & tm)
|
||||
{
|
||||
// warning, assumes Orthogonal matrix
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
Center = tm * Center;
|
||||
#else
|
||||
tm.mulVector3(Center, Center);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* SphereClass::Volume -- returns the volume of this sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/22/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline float SphereClass::Volume(void) const
|
||||
{
|
||||
return (4.0 / 3.0) * WWMATH_PI * (Radius * Radius * Radius);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* SphereClass::operator+= -- 'Add' a sphere to this one *
|
||||
* *
|
||||
* Expands 'this' sphere to also enclose the given sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline SphereClass & SphereClass::operator += (const SphereClass & s)
|
||||
{
|
||||
Add_Sphere(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* SphereClass::operator *= -- transform this sphere by the given radius *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline SphereClass & SphereClass::operator *= (const Matrix3D & m)
|
||||
{
|
||||
Init(m, Center, Radius);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Spheres_Intersect -- test whether two spheres intersect *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline bool Spheres_Intersect(const SphereClass & s0,const SphereClass & s1)
|
||||
{
|
||||
Vector3 delta = s0.Center - s1.Center;
|
||||
float dist2 = Vector3::Dot_Product(delta, delta);
|
||||
|
||||
if (dist2 < (s0.Radius + s1.Radius) * (s0.Radius + s1.Radius)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Add_Spheres -- Add two spheres together, creating sphere which encloses both *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline SphereClass Add_Spheres(const SphereClass & s0, const SphereClass & s1)
|
||||
{
|
||||
if (s0.Radius == 0.0f) {
|
||||
return s1;
|
||||
} else {
|
||||
SphereClass result(s0);
|
||||
result.Add_Sphere(s1);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* operator + -- Add two spheres together, creating a sphere which encloses both *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline SphereClass operator + (const SphereClass & s0,const SphereClass & s1)
|
||||
{
|
||||
return Add_Spheres(s0,s1);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Transform Sphere -- transform a sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline SphereClass Transform_Sphere(const Matrix3D & m, const SphereClass & s)
|
||||
{
|
||||
// Warning, assumes Orthogonal matrix
|
||||
return SphereClass(m,s.Center,s.Radius);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Transform_Sphere -- transform a sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline void Transform_Sphere(const Matrix3D & m, const SphereClass & s,SphereClass & res)
|
||||
{
|
||||
// warning, assumes Orthogonal matrix
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
res.Center = m*s.Center;
|
||||
#else
|
||||
m.mulVector3(s.Center, res.Center);
|
||||
#endif
|
||||
res.Radius = s.Radius;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* operator * -- Transform a sphere *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 8/12/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
inline SphereClass operator * (const Matrix3D & m, const SphereClass & s)
|
||||
{
|
||||
return Transform_Sphere(m,s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
248
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/tcbspline.cpp
Normal file
248
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/tcbspline.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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:: /VSS_Sync/wwmath/tcbspline.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 6/13/01 2:18p $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "tcbspline.h"
|
||||
#include "wwdebug.h"
|
||||
#include "persistfactory.h"
|
||||
#include "wwmathids.h"
|
||||
#include "wwhack.h"
|
||||
|
||||
|
||||
/*
|
||||
** Force-Link this module because the linker can't detect that we actually need it...
|
||||
*/
|
||||
DECLARE_FORCE_LINK(tcbspline);
|
||||
|
||||
/*
|
||||
** Save-Load stuff
|
||||
*/
|
||||
SimplePersistFactoryClass<TCBSpline3DClass,WWMATH_CHUNKID_TCBSPLINE3D> _TCBSpline3DFactory;
|
||||
|
||||
enum
|
||||
{
|
||||
// ID's used by TCBSpline3D
|
||||
TCB3D_CHUNK_HERMITE3D = 0x02071009,
|
||||
TCB3D_CHUNK_PARAMS,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** TCBSpline3DClass Implemenation
|
||||
*/
|
||||
|
||||
int TCBSpline3DClass::Add_Key(const Vector3 & point,float t)
|
||||
{
|
||||
int index;
|
||||
index = HermiteSpline3DClass::Add_Key(point,t);
|
||||
|
||||
TCBClass params;
|
||||
params.Tension = 0.0f;
|
||||
params.Continuity = 0.0f;
|
||||
params.Bias = 0.0f;
|
||||
Params.Insert(index,params);
|
||||
return index;
|
||||
}
|
||||
|
||||
void TCBSpline3DClass::Remove_Key(int i)
|
||||
{
|
||||
HermiteSpline3DClass::Remove_Key(i);
|
||||
Params.Delete(i);
|
||||
}
|
||||
|
||||
void TCBSpline3DClass::Clear_Keys(void)
|
||||
{
|
||||
HermiteSpline3DClass::Clear_Keys();
|
||||
Params.Clear();
|
||||
}
|
||||
|
||||
void TCBSpline3DClass::Set_TCB_Params(int i,float tension,float continuity,float bias)
|
||||
{
|
||||
WWASSERT(i >= 0);
|
||||
WWASSERT(i < Params.Count());
|
||||
Params[i].Tension = tension;
|
||||
Params[i].Continuity = continuity;
|
||||
Params[i].Bias = bias;
|
||||
TangentsDirty = true;
|
||||
}
|
||||
|
||||
void TCBSpline3DClass::Get_TCB_Params(int i,float *tension,float *continuity,float *bias)
|
||||
{
|
||||
if (tension) *tension = Params[i].Tension;
|
||||
if (continuity) *continuity = Params[i].Continuity;
|
||||
if (bias) *bias = Params[i].Bias;
|
||||
}
|
||||
|
||||
void TCBSpline3DClass::Update_Tangents(void)
|
||||
{
|
||||
if (Keys.Count() < 2) {
|
||||
for (int i=0; i<Keys.Count(); i++) {
|
||||
Tangents[0].InTangent.Set(0,0,0);
|
||||
Tangents[0].OutTangent.Set(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
// First and Last Key:
|
||||
// Only need to compute the OutTangent for key[0] and the InTangent for key[end]
|
||||
int end = Keys.Count() - 1;
|
||||
Tangents[0].InTangent.Set(0,0,0);
|
||||
Tangents[end].OutTangent.Set(0,0,0);
|
||||
|
||||
if (IsLooping) {
|
||||
|
||||
// This really only works if the start and end points have the same position...
|
||||
// Also just using the TCB params from p0 for both
|
||||
float k0 = 0.5f * ((1-Params[0].Tension) * (1-Params[0].Continuity) * (1-Params[0].Bias));
|
||||
float k1 = 0.5f * ((1-Params[0].Tension) * (1+Params[0].Continuity) * (1+Params[0].Bias));
|
||||
float k2 = 0.5f * ((1-Params[0].Tension) * (1+Params[0].Continuity) * (1-Params[0].Bias));
|
||||
float k3 = 0.5f * ((1-Params[0].Tension) * (1-Params[0].Continuity) * (1+Params[0].Bias));
|
||||
|
||||
Vector3 dp_in;
|
||||
Vector3 dp_out;
|
||||
Vector3::Subtract(Keys[0].Point,Keys[end-1].Point,&dp_in);
|
||||
Vector3::Subtract(Keys[1].Point,Keys[0].Point,&dp_out);
|
||||
|
||||
Vector3::Add(k0*dp_in, k1*dp_out, &Tangents[end].InTangent);
|
||||
Vector3::Add(k2*dp_out, k3*dp_in, &Tangents[0].OutTangent);
|
||||
|
||||
} else {
|
||||
|
||||
float k2 = 0.25f * ((1-Params[0].Tension) * (1+Params[0].Continuity) * (1-Params[0].Bias));
|
||||
float k3 = 0.25f * ((1-Params[0].Tension) * (1-Params[0].Continuity) * (1+Params[0].Bias));
|
||||
|
||||
Vector3 dp_in;
|
||||
Vector3 dp_out;
|
||||
Vector3::Subtract(Keys[1].Point,Keys[0].Point,&dp_out);
|
||||
dp_in = dp_out;
|
||||
Vector3::Add(k2*dp_out, k3*dp_in, &Tangents[0].OutTangent);
|
||||
|
||||
float k0 = 0.25f * ((1-Params[0].Tension) * (1-Params[0].Continuity) * (1-Params[0].Bias));
|
||||
float k1 = 0.25f * ((1-Params[0].Tension) * (1+Params[0].Continuity) * (1+Params[0].Bias));
|
||||
Vector3::Subtract(Keys[end].Point,Keys[end-1].Point,&dp_in);
|
||||
dp_out = dp_in;
|
||||
Vector3::Add(k0*dp_out, k1*dp_in, &Tangents[end].InTangent);
|
||||
}
|
||||
|
||||
float total_time = (Keys[1].Time - Keys[0].Time) + (Keys[end].Time - Keys[end-1].Time);
|
||||
float in_factor = 2.0f * (Keys[end].Time - Keys[end-1].Time) / total_time;
|
||||
float out_factor = 2.0f * (Keys[1].Time - Keys[0].Time) / total_time;
|
||||
Tangents[end].InTangent *= in_factor;
|
||||
Tangents[0].OutTangent *= out_factor;
|
||||
|
||||
|
||||
// Now compute the tangents of all of the normal keys...
|
||||
for (int pi=1;pi<Keys.Count() - 1; pi++) {
|
||||
|
||||
float k0 = 0.5f * ((1-Params[pi].Tension) * (1-Params[pi].Continuity) * (1-Params[pi].Bias));
|
||||
float k1 = 0.5f * ((1-Params[pi].Tension) * (1+Params[pi].Continuity) * (1+Params[pi].Bias));
|
||||
float k2 = 0.5f * ((1-Params[pi].Tension) * (1+Params[pi].Continuity) * (1-Params[pi].Bias));
|
||||
float k3 = 0.5f * ((1-Params[pi].Tension) * (1-Params[pi].Continuity) * (1+Params[pi].Bias));
|
||||
|
||||
Vector3 dp_in;
|
||||
Vector3 dp_out;
|
||||
Vector3::Subtract(Keys[pi].Point,Keys[pi-1].Point,&dp_in);
|
||||
Vector3::Subtract(Keys[pi+1].Point,Keys[pi].Point,&dp_out);
|
||||
|
||||
Vector3::Add(k0*dp_out, k1*dp_in, &Tangents[pi].InTangent);
|
||||
Vector3::Add(k2*dp_out, k3*dp_in, &Tangents[pi].OutTangent);
|
||||
|
||||
float total_time = (Keys[pi+1].Time - Keys[pi-1].Time);
|
||||
float in_factor = 2.0f * (Keys[pi].Time - Keys[pi-1].Time) / total_time;
|
||||
float out_factor = 2.0f * (Keys[pi+1].Time - Keys[pi].Time) / total_time;
|
||||
|
||||
Tangents[pi].InTangent *= in_factor; // compensating for un-even keys
|
||||
Tangents[pi].OutTangent *= out_factor;
|
||||
|
||||
}
|
||||
TangentsDirty = false;
|
||||
}
|
||||
|
||||
const PersistFactoryClass & TCBSpline3DClass::Get_Factory(void) const
|
||||
{
|
||||
return _TCBSpline3DFactory;
|
||||
}
|
||||
|
||||
bool TCBSpline3DClass::Save(ChunkSaveClass &csave)
|
||||
{
|
||||
csave.Begin_Chunk(TCB3D_CHUNK_HERMITE3D);
|
||||
HermiteSpline3DClass::Save(csave);
|
||||
csave.End_Chunk();
|
||||
|
||||
csave.Begin_Chunk(TCB3D_CHUNK_PARAMS);
|
||||
for (int i=0; i<Params.Count(); i++) {
|
||||
csave.Write(&(Params[i].Tension),sizeof(Params[i].Tension));
|
||||
csave.Write(&(Params[i].Continuity),sizeof(Params[i].Continuity));
|
||||
csave.Write(&(Params[i].Bias),sizeof(Params[i].Bias));
|
||||
}
|
||||
csave.End_Chunk();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCBSpline3DClass::Load(ChunkLoadClass &cload)
|
||||
{
|
||||
int i;
|
||||
TCBClass param;
|
||||
|
||||
// reset the keys
|
||||
Params.Delete_All();
|
||||
|
||||
// read in the chunks
|
||||
while (cload.Open_Chunk()) {
|
||||
|
||||
switch(cload.Cur_Chunk_ID())
|
||||
{
|
||||
case TCB3D_CHUNK_HERMITE3D:
|
||||
HermiteSpline3DClass::Load(cload);
|
||||
break;
|
||||
|
||||
case TCB3D_CHUNK_PARAMS:
|
||||
for (i=0; i<Keys.Count(); i++) {
|
||||
cload.Read(&(param.Tension),sizeof(param.Tension));
|
||||
cload.Read(&(param.Continuity),sizeof(param.Continuity));
|
||||
cload.Read(&(param.Bias),sizeof(param.Bias));
|
||||
Params.Add(param);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
|
||||
break;
|
||||
}
|
||||
cload.Close_Chunk();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
86
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/tcbspline.h
Normal file
86
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/tcbspline.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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:: /VSS_Sync/wwmath/tcbspline.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 6/13/01 2:18p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef TCBSPLINE_H
|
||||
#define TCBSPLINE_H
|
||||
|
||||
#include "hermitespline.h"
|
||||
|
||||
/*
|
||||
** TCBSpline3DClass
|
||||
** Tension-Continuity-Bias splines. Otherwise known as Kochanek-Bartels cubic splines
|
||||
*/
|
||||
class TCBSpline3DClass : public HermiteSpline3DClass
|
||||
{
|
||||
public:
|
||||
|
||||
virtual int Add_Key(const Vector3 & point,float t);
|
||||
virtual void Remove_Key(int i);
|
||||
virtual void Clear_Keys(void);
|
||||
|
||||
virtual void Set_TCB_Params(int i,float tension,float continuity,float bias);
|
||||
virtual void Get_TCB_Params(int i,float *tension,float *continuity,float *bias);
|
||||
|
||||
void Update_Tangents(void);
|
||||
|
||||
// save-load support
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
|
||||
protected:
|
||||
|
||||
class TCBClass
|
||||
{
|
||||
public:
|
||||
float Tension;
|
||||
float Continuity;
|
||||
float Bias;
|
||||
bool operator == (const TCBClass & that) { return ((Tension == that.Tension) && (Continuity == that.Continuity) && (Bias == that.Bias)); }
|
||||
bool operator != (const TCBClass & that) { return !TCBClass::operator == (that); }
|
||||
};
|
||||
|
||||
DynamicVectorClass<TCBClass> Params;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
363
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/tri.cpp
Normal file
363
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/tri.cpp
Normal file
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/tri.cpp $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 5/03/01 3:41p $*
|
||||
* *
|
||||
* $Revision:: 8 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* TriClass::Find_Dominant_Plane -- returns indices of the axes of the dominant plane *
|
||||
* TriClass::Contains_Point -- performs 2D point-in-triangle test. *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "tri.h"
|
||||
#include "vector2.h"
|
||||
|
||||
|
||||
struct FDPRec
|
||||
{
|
||||
int axis1;
|
||||
int axis2;
|
||||
int axis3;
|
||||
};
|
||||
|
||||
static inline void find_dominant_plane_fast(const TriClass & tri, FDPRec& info)
|
||||
{
|
||||
static const FDPRec dominance[3] =
|
||||
{
|
||||
{ 1, 2, 0 }, // Dominant is the X axis
|
||||
{ 0, 2, 1 }, // Dominant is the Y axis
|
||||
{ 0, 1, 2 } // Dominant is the Z axis
|
||||
};
|
||||
|
||||
/*
|
||||
** Find the largest component of the normal
|
||||
*/
|
||||
float x = WWMath::Fabs(tri.N->X);
|
||||
float y = WWMath::Fabs(tri.N->Y);
|
||||
float z = WWMath::Fabs(tri.N->Z);
|
||||
|
||||
float val = x;
|
||||
int ni = 0;
|
||||
|
||||
if (y > val)
|
||||
{
|
||||
ni = 1;
|
||||
val = y;
|
||||
}
|
||||
|
||||
if (z > val)
|
||||
{
|
||||
ni = 2;
|
||||
}
|
||||
|
||||
info = dominance[ni];
|
||||
}
|
||||
|
||||
static inline void find_dominant_plane(const TriClass & tri, int * axis1,int * axis2,int * axis3)
|
||||
{
|
||||
/*
|
||||
** Find the largest component of the normal
|
||||
*/
|
||||
int ni = 0;
|
||||
float x = WWMath::Fabs(tri.N->X);
|
||||
float y = WWMath::Fabs(tri.N->Y);
|
||||
float z = WWMath::Fabs(tri.N->Z);
|
||||
float val = x;
|
||||
|
||||
if (y > val) {
|
||||
ni = 1;
|
||||
val = y;
|
||||
}
|
||||
|
||||
if (z > val) {
|
||||
ni = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
** return the indices of the two axes perpendicular
|
||||
*/
|
||||
switch (ni)
|
||||
{
|
||||
case 0:
|
||||
// Dominant is the X axis
|
||||
*axis1 = 1;
|
||||
*axis2 = 2;
|
||||
*axis3 = 0;
|
||||
break;
|
||||
case 1:
|
||||
// Dominant is the Y axis
|
||||
*axis1 = 0;
|
||||
*axis2 = 2;
|
||||
*axis3 = 1;
|
||||
break;
|
||||
case 2:
|
||||
// Dominant is the Z axis
|
||||
*axis1 = 0;
|
||||
*axis2 = 1;
|
||||
*axis3 = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* TriClass::Find_Dominant_Plane -- returns indices of the axes of the dominant plane *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/24/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
void TriClass::Find_Dominant_Plane(int * axis1,int * axis2) const
|
||||
{
|
||||
/*
|
||||
** Find the largest component of the normal
|
||||
*/
|
||||
int ni = 0;
|
||||
float x = WWMath::Fabs(N->X);
|
||||
float y = WWMath::Fabs(N->Y);
|
||||
float z = WWMath::Fabs(N->Z);
|
||||
float val = x;
|
||||
|
||||
if (y > val) {
|
||||
ni = 1;
|
||||
val = y;
|
||||
}
|
||||
|
||||
if (z > val) {
|
||||
ni = 2;
|
||||
}
|
||||
|
||||
/*
|
||||
** return the indices of the two axes perpendicular
|
||||
*/
|
||||
switch (ni)
|
||||
{
|
||||
case 0:
|
||||
// Dominant is the X axis
|
||||
*axis1 = 1;
|
||||
*axis2 = 2;
|
||||
break;
|
||||
case 1:
|
||||
// Dominant is the Y axis
|
||||
*axis1 = 0;
|
||||
*axis2 = 2;
|
||||
break;
|
||||
case 2:
|
||||
// Dominant is the Z axis
|
||||
*axis1 = 0;
|
||||
*axis2 = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* TriClass::Contains_Point -- performs 2D point-in-triangle test. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* Assumes that the point is in the plane of the triangle... use this after you've intersected *
|
||||
* a ray with the plane of the triangle. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 3/24/99 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
bool TriClass::Contains_Point(const Vector3 & ipoint) const
|
||||
{
|
||||
#if 0
|
||||
/*
|
||||
** Perform the test in 2d on the plane which the normal
|
||||
** is most perpendicular to. (copied from E.Cosky's intersection code)
|
||||
*/
|
||||
int axis1 = 0;
|
||||
int axis2 = 0;
|
||||
Find_Dominant_Plane(&axis1,&axis2);
|
||||
|
||||
#if 1
|
||||
unsigned char flags; // dummy variable passed into function and not used here
|
||||
return Point_In_Triangle_2D(*V[0], *V[1], *V[2], ipoint, axis1, axis2, flags);
|
||||
#else
|
||||
float u0 = ipoint[axis1] - (*V[0])[axis1];
|
||||
float v0 = ipoint[axis2] - (*V[0])[axis2];
|
||||
|
||||
/*
|
||||
** determine the 2d vectors on the dominant plane from the first vertex to the other two
|
||||
*/
|
||||
float u1 = (*V[1])[axis1] - (*V[0])[axis1];
|
||||
float v1 = (*V[1])[axis2] - (*V[0])[axis2];
|
||||
float u2 = (*V[2])[axis1] - (*V[0])[axis1];
|
||||
float v2 = (*V[2])[axis2] - (*V[0])[axis2];
|
||||
|
||||
float alpha, beta;
|
||||
bool intersect = false;
|
||||
|
||||
// calculate alpha and beta as normalized (0..1) percentages across the 2d projected triangle
|
||||
// and do bounds checking (sum <= 1) to determine whether or not the triangle intersection occurs.
|
||||
if (u1 == 0) {
|
||||
beta = u0 / u2;
|
||||
if ((beta >= 0) && (beta <= 1)) {
|
||||
alpha = (v0 - beta * v2) / v1;
|
||||
intersect = ((alpha >= 0) && ((alpha + beta) <= 1 + WWMATH_EPSILON));
|
||||
}
|
||||
} else {
|
||||
beta = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
|
||||
if ((beta >= 0) && (beta <= 1)) {
|
||||
alpha = (u0 - beta * u2) / u1;
|
||||
intersect = ((alpha >= 0) && ((alpha + beta) <= 1 + WWMATH_EPSILON));
|
||||
}
|
||||
}
|
||||
|
||||
return intersect;
|
||||
#endif
|
||||
#endif
|
||||
/*
|
||||
** New cross-product based point-containment
|
||||
*/
|
||||
#if 0
|
||||
int vi;
|
||||
int axis3 = 0;
|
||||
|
||||
for (vi=0; vi<3; vi++) {
|
||||
if ((axis1 != vi) && (axis2 != vi)) axis3 = vi;
|
||||
}
|
||||
|
||||
Vector3 test_point = ipoint;
|
||||
test_point[axis3] = 0.0f;
|
||||
|
||||
Vector3 points[3];
|
||||
for (vi=0; vi<3; vi++) {
|
||||
points[vi] = *(V[vi]);
|
||||
points[vi][axis3] = 0.0f;
|
||||
}
|
||||
|
||||
bool side[3];
|
||||
Vector3 edge;
|
||||
Vector3 cross;
|
||||
Vector3 dp;
|
||||
|
||||
for (vi=0; vi<3; vi++) {
|
||||
edge = points[(vi+1)%3] - points[vi];
|
||||
dp = test_point - points[vi];
|
||||
|
||||
Vector3::Cross_Product(dp,edge,&cross);
|
||||
side[vi] = (cross[axis3] > 0.0f);
|
||||
}
|
||||
|
||||
bool my_intersect = ((side[0] == side[1]) && (side[1] == side[2]));
|
||||
return my_intersect;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** "Optimized" version
|
||||
*/
|
||||
#if 1
|
||||
#if 0
|
||||
|
||||
// srj opto version
|
||||
/// @todo srj -- profile me to see if this is actually faster
|
||||
|
||||
FDPRec info;
|
||||
find_dominant_plane_fast(*this, info);
|
||||
|
||||
/*
|
||||
** Compute the 2D cross product of edge0 with a vector to the point
|
||||
*/
|
||||
|
||||
float edge_x, edge_y, dp_x, dp_y, cross;
|
||||
bool side0, side1, side2;
|
||||
|
||||
edge_x = (*V[1])[info.axis1] - (*V[0])[info.axis1];
|
||||
edge_y = (*V[1])[info.axis2] - (*V[0])[info.axis2];
|
||||
dp_x = ipoint[info.axis1] - (*V[0])[info.axis1];
|
||||
dp_y = ipoint[info.axis2] - (*V[0])[info.axis2];
|
||||
cross = edge_x * dp_y - edge_y * dp_x;
|
||||
side0 = (cross >= 0.0f);
|
||||
|
||||
edge_x = (*V[2])[info.axis1] - (*V[1])[info.axis1];
|
||||
edge_y = (*V[2])[info.axis2] - (*V[1])[info.axis2];
|
||||
dp_x = ipoint[info.axis1] - (*V[1])[info.axis1];
|
||||
dp_y = ipoint[info.axis2] - (*V[1])[info.axis2];
|
||||
cross = edge_x * dp_y - edge_y * dp_x;
|
||||
side1 = (cross >= 0.0f);
|
||||
|
||||
edge_x = (*V[0])[info.axis1] - (*V[2])[info.axis1];
|
||||
edge_y = (*V[0])[info.axis2] - (*V[2])[info.axis2];
|
||||
dp_x = ipoint[info.axis1] - (*V[2])[info.axis1];
|
||||
dp_y = ipoint[info.axis2] - (*V[2])[info.axis2];
|
||||
cross = edge_x * dp_y - edge_y * dp_x;
|
||||
side2 = (cross >= 0.0f);
|
||||
|
||||
bool my_intersect = ((side0 == side1) && (side1 == side2));
|
||||
return my_intersect;
|
||||
|
||||
#else
|
||||
int vi;
|
||||
int axis1 = 0;
|
||||
int axis2 = 0;
|
||||
int axis3 = 0;
|
||||
|
||||
find_dominant_plane(*this,&axis1,&axis2,&axis3);
|
||||
|
||||
bool side[3];
|
||||
|
||||
/*
|
||||
** Compute the 2D cross product of edge0 with a vector to the point
|
||||
*/
|
||||
Vector2 edge;
|
||||
Vector2 dp;
|
||||
|
||||
for (vi=0; vi<3; vi++) {
|
||||
|
||||
int va=vi;
|
||||
int vb=(vi+1)%3;
|
||||
|
||||
edge.Set((*V[vb])[axis1] - (*V[va])[axis1] , (*V[vb])[axis2] - (*V[va])[axis2]);
|
||||
dp.Set(ipoint[axis1] - (*V[va])[axis1] , ipoint[axis2] - (*V[va])[axis2]);
|
||||
float cross = edge.X * dp.Y - edge.Y * dp.X;
|
||||
side[vi] = (cross >= 0.0f);
|
||||
}
|
||||
|
||||
bool my_intersect = ((side[0] == side[1]) && (side[1] == side[2]));
|
||||
return my_intersect;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
306
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/tri.h
Normal file
306
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/tri.h
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/tri.h $*
|
||||
* *
|
||||
* Author:: Greg_h *
|
||||
* *
|
||||
* $Modtime:: 5/04/01 8:35p $*
|
||||
* *
|
||||
* $Revision:: 14 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef TRI_H
|
||||
#define TRI_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector4.h"
|
||||
#include "vector3.h"
|
||||
#include "vector2.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
/**
|
||||
** TriClass
|
||||
** When the math library needs to deal with triangles, this will be the form used.
|
||||
** The initial reason for this class is for Commando's collision detection code. Initially
|
||||
** I wrote custom code inside the render object for the terrain to perform collision
|
||||
** detection. Moving the low-level geometrical collision code into the math library makes it
|
||||
** more re-useable and independent from changes in the rendering code.
|
||||
*/
|
||||
class TriClass
|
||||
{
|
||||
public:
|
||||
|
||||
const Vector3 * N;
|
||||
const Vector3 * V[3];
|
||||
|
||||
void Compute_Normal()
|
||||
{
|
||||
assert(N);
|
||||
assert(V[0]);
|
||||
assert(V[1]);
|
||||
assert(V[2]);
|
||||
|
||||
Vector3::Cross_Product(*(V[1])-*(V[0]),*(V[2])-*(V[0]),(Vector3 *)N);
|
||||
((Vector3 *)N)->Normalize();
|
||||
}
|
||||
|
||||
|
||||
bool Contains_Point(const Vector3 & ipoint) const;
|
||||
void Find_Dominant_Plane(int * axis1,int * axis2) const;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Utility functions:
|
||||
** Functions which have to do with triangles but not neccessarily with TriClass - usually used
|
||||
** by TriClass but also available for use elsewhere.
|
||||
*/
|
||||
|
||||
// Enums for raycast flags (currently used only for semi-infinite axis-aligned rays)
|
||||
enum
|
||||
{
|
||||
TRI_RAYCAST_FLAG_NONE = 0x00,
|
||||
TRI_RAYCAST_FLAG_HIT_EDGE = 0x01,
|
||||
TRI_RAYCAST_FLAG_START_IN_TRI = 0x02
|
||||
};
|
||||
|
||||
// This function does a pure 2D point-in-triangle test. We pass in 3D points both for the
|
||||
// triangle and test points, but we also pass in the two axes to use (the third axis is ignored,
|
||||
// so we are actually testing the projection of the four points onto one of the axis planes). The
|
||||
// triangle points are not assumed to be in any particular winding order (that is checked for
|
||||
// internally). It is used internally by TriClass::Contains_Point(), and may be used elsewhere.
|
||||
// If the ray intersects the camera at an edge we also count it as an intersection. We set a bit
|
||||
// in 'flags' to true in this case (some users of this function need this extra information and
|
||||
// it is very cheap to compute). We do not modify 'flags' if no edges are hit, so it must be
|
||||
// initialized outside this function if its value is to be used.
|
||||
inline bool Point_In_Triangle_2D(const Vector3 &tri_point0, const Vector3 &tri_point1,
|
||||
const Vector3 &tri_point2, const Vector3 &test_point, int axis_1, int axis_2,
|
||||
unsigned char &flags)
|
||||
{
|
||||
// The function is based on checking signs of determinants, or in a more visually intuitive
|
||||
// sense, checking on which side of a line a point lies. For example, if the points run in
|
||||
// counter-clockwise order, the interior of the triangle is the intersection of the three
|
||||
// half-planes to the left of the directed infinite lines along P0 to P1, P1 to P2, P2 to P0.
|
||||
// Therefore the test point is in the triangle iff it is to the left of all three lines (if
|
||||
// the points are in clockwise order, we check if it is to the right of the lines).
|
||||
Vector2 p0p1(tri_point1[axis_1] - tri_point0[axis_1], tri_point1[axis_2] - tri_point0[axis_2]);
|
||||
Vector2 p1p2(tri_point2[axis_1] - tri_point1[axis_1], tri_point2[axis_2] - tri_point1[axis_2]);
|
||||
Vector2 p2p0(tri_point0[axis_1] - tri_point2[axis_1], tri_point0[axis_2] - tri_point2[axis_2]);
|
||||
|
||||
// Check which side P2 is relative to P0P1. The sign of this test must equal the sign of all
|
||||
// three tests between the lines and the test point for the test point to be inside the
|
||||
// triangle. (this test will also tell us if the three points are colinear - if the triangle
|
||||
// is degenerate).
|
||||
Vector2 p0p2(tri_point2[axis_1] - tri_point0[axis_1], tri_point2[axis_2] - tri_point0[axis_2]);
|
||||
float p0p1p2 = Vector2::Perp_Dot_Product(p0p1, p0p2);
|
||||
if (p0p1p2 != 0.0f) {
|
||||
|
||||
// The triangle is not degenerate - test three sides
|
||||
float side_factor = p0p1p2 > 0.0f ? 1.0f : -1.0f;
|
||||
float factors[3];
|
||||
|
||||
// Now perform tests
|
||||
Vector2 p0pT(test_point[axis_1] - tri_point0[axis_1], test_point[axis_2] - tri_point0[axis_2]);
|
||||
factors[0] = Vector2::Perp_Dot_Product(p0p1, p0pT);
|
||||
if (factors[0] * side_factor < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
Vector2 p1pT(test_point[axis_1] - tri_point1[axis_1], test_point[axis_2] - tri_point1[axis_2]);
|
||||
factors[1] = Vector2::Perp_Dot_Product(p1p2, p1pT);
|
||||
if (factors[1] * side_factor < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
Vector2 p2pT(test_point[axis_1] - tri_point2[axis_1], test_point[axis_2] - tri_point2[axis_2]);
|
||||
factors[2] = Vector2::Perp_Dot_Product(p2p0, p2pT);
|
||||
if (factors[2] * side_factor < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
if ((factors[0] == 0.0f) || (factors[1] == 0.0f) || (factors[2] == 0.0f)) flags |= TRI_RAYCAST_FLAG_HIT_EDGE;
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
// The triangle is degenerate. This should be a rare case, so it does not matter much if it
|
||||
// is a little slower than the non-colinear case.
|
||||
|
||||
// Find the two outer points along the triangle's line ('start' and 'end' points)
|
||||
float p0p1dist2 = p0p1.Length2();
|
||||
float p1p2dist2 = p1p2.Length2();
|
||||
float p2p0dist2 = p1p2.Length2();
|
||||
float max_dist2;
|
||||
Vector2 pSpE, pSpT; // 'end' point, test point - both in 'start' points' frame
|
||||
if (p0p1dist2 > p1p2dist2) {
|
||||
if (p0p1dist2 > p2p0dist2) {
|
||||
// points 0 and 1 are the 'outer' points. 0 is 'start' and 1 is 'end'.
|
||||
pSpE = p0p1;
|
||||
pSpT.Set(test_point[axis_1] - tri_point0[axis_1], test_point[axis_2] - tri_point0[axis_2]);
|
||||
max_dist2 = p0p1dist2;
|
||||
} else {
|
||||
// points 0 and 2 are the 'outer' points. 2 is 'start' and 0 is 'end'.
|
||||
pSpE = p2p0;
|
||||
pSpT.Set(test_point[axis_1] - tri_point2[axis_1], test_point[axis_2] - tri_point2[axis_2]);
|
||||
max_dist2 = p2p0dist2;
|
||||
}
|
||||
} else {
|
||||
if (p1p2dist2 > p2p0dist2) {
|
||||
// points 1 and 2 are the 'outer' points. 1 is 'start' and 2 is 'end'.
|
||||
pSpE = p1p2;
|
||||
pSpT.Set(test_point[axis_1] - tri_point1[axis_1], test_point[axis_2] - tri_point1[axis_2]);
|
||||
max_dist2 = p1p2dist2;
|
||||
} else {
|
||||
// points 0 and 2 are the 'outer' points. 2 is 'start' and 0 is 'end'.
|
||||
pSpE = p2p0;
|
||||
pSpT.Set(test_point[axis_1] - tri_point2[axis_1], test_point[axis_2] - tri_point2[axis_2]);
|
||||
max_dist2 = p2p0dist2;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_dist2 != 0.0f) {
|
||||
// Triangle is line segment, check if test point is colinear with it
|
||||
if (Vector2::Perp_Dot_Product(pSpE, pSpT)) {
|
||||
// Not colinear
|
||||
return false;
|
||||
} else {
|
||||
// Colinear - is test point's distance from start and end <= segment length?
|
||||
Vector2 pEpT = pSpT - pSpE;
|
||||
if (pSpT.Length2() <= max_dist2 && pEpT.Length2() <= max_dist2) {
|
||||
flags |= TRI_RAYCAST_FLAG_HIT_EDGE;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// All triangle points coincide, check if test point coincides with them
|
||||
if (pSpT.Length2() == 0.0f) {
|
||||
flags |= TRI_RAYCAST_FLAG_HIT_EDGE;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function tests a semi-infinite axis-aligned ray vs. a triangle.
|
||||
// The inputs are blah blah blah
|
||||
inline bool Cast_Semi_Infinite_Axis_Aligned_Ray_To_Triangle(const Vector3 &tri_point0,
|
||||
const Vector3 &tri_point1, const Vector3 &tri_point2, const Vector4 &tri_plane,
|
||||
const Vector3 &ray_start, int axis_r, int axis_1, int axis_2, int direction,
|
||||
unsigned char & flags)
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
// First check infinite ray vs. triangle (2D check)
|
||||
unsigned char flags_2d = TRI_RAYCAST_FLAG_NONE;
|
||||
if (Point_In_Triangle_2D(tri_point0, tri_point1, tri_point2, ray_start, axis_1, axis_2, flags_2d)) {
|
||||
|
||||
// NOTE: SR plane equations, unlike WWMath's PlaneClass, use the Ax+By+Cz+D = 0
|
||||
// representation. It can also be viewed as C0x+C1y+C2z+C3 = dist where dist is the
|
||||
// signed distance from the plane (and therefore the plane is defined as those points
|
||||
// where dist = 0). Now that we know that the projection along the ray is inside the
|
||||
// triangle, determining whether the ray hits the triangle is a matter of determining
|
||||
// whether the start point is on the triangle plane's "anti-rayward side" (the side
|
||||
// which the ray points away from).
|
||||
// To determine this, we will use C[axis_r] (the plane coefficient of the ray axis).
|
||||
// This coefficient is positive if the positive direction of the ray axis points into
|
||||
// the planes' positive halfspace and negative if it points into the planes' negative
|
||||
// halfspace (it is zero if the ray axis is parallel to the triangle plane). If we
|
||||
// multiply this by 'sign' which is defined to be -1.0 if 'direction' equals 0 and
|
||||
// 1.0 if 'direction' equals 1, we will get a number which is positive or negative
|
||||
// depending on which halfspace the ray itself (as opposed to the rays axis) points
|
||||
// towards. If we further multiply this by dist(start point) - the result of plugging
|
||||
// the start point into the plane equation - we will get a number which is positive
|
||||
// if the start point is on the 'rayward side' (ray does not intersect the triangle)
|
||||
// and is negative if the start point is on the 'anti-rayward side' (ray does
|
||||
// intersect triangle). In either of these two cases we are done.
|
||||
// (see below for what happens when the result is zero - more checks need to be made).
|
||||
static const float sign[2] = {-1.0f, 1.0f };
|
||||
float result = tri_plane[axis_r] * sign[direction] * (tri_plane.X * ray_start.X +
|
||||
tri_plane.Y * ray_start.Y + tri_plane.Z * ray_start.Z + tri_plane.W);
|
||||
if (result < 0.0f) {
|
||||
// Intersection!
|
||||
flags |= (flags_2d & TRI_RAYCAST_FLAG_HIT_EDGE);
|
||||
retval = true;
|
||||
} else {
|
||||
if (result == 0.0f) {
|
||||
// If the result is 0, this means either the ray is parallel to the triangle
|
||||
// plane or the start point is embedded in the triangle plane. Note that since
|
||||
// the start point passed the 2D check, then if the ray is parallel the start
|
||||
// point must also be embedded in the triangle plane. This leaves us with two
|
||||
// cases:
|
||||
// A) The ray is not parallel to the plane - in this case the start point is
|
||||
// embedded in the triangle. We report an intersection, bitwise OR the edge
|
||||
// result from the 2D check into the 'edge hit' flag and set the 'start in tri'
|
||||
// flag.
|
||||
// B) The ray is parallel to the plane. In this case the result of the 2D test
|
||||
// tells us that the infinite line intersects the triangle (actually is
|
||||
// embedded in the triangle along part of its length), but we do not know
|
||||
// whether the semi-infinite ray also does so. We simplify things by not
|
||||
// counting such an 'intersection'. There are four reasons behind this:
|
||||
// 1. It differs from a 'normal' intersection (which has one intersecting
|
||||
// point) - there are infinitely many intersecting points.
|
||||
// 2. Moving the plane by an infinitesimally small amount to either side will
|
||||
// cause the ray to no longer touch the plane.
|
||||
// 3. This will not affect results for the known uses of this function.
|
||||
// 4. By doing so we avoid having to code up a bunch of complex tests.
|
||||
// Therefore in case B) we just report no intersection. We still need to find
|
||||
// out whether the point is embedded in the triangle (for setting the flag) so
|
||||
// we do another simple 2D test on the dominant plane.
|
||||
if (tri_plane[axis_r]) {
|
||||
// Case A)
|
||||
flags |= (flags_2d & TRI_RAYCAST_FLAG_HIT_EDGE);
|
||||
flags |= TRI_RAYCAST_FLAG_START_IN_TRI;
|
||||
retval = true;
|
||||
} else {
|
||||
// Case B) - test if point in tri (we know it is in plane, so we can use
|
||||
// TriClass function)
|
||||
TriClass tri;
|
||||
tri.V[0] = &tri_point0;
|
||||
tri.V[1] = &tri_point1;
|
||||
tri.V[2] = &tri_point2;
|
||||
tri.N = (Vector3*)&tri_plane;
|
||||
if (tri.Contains_Point(ray_start)) {
|
||||
flags |= TRI_RAYCAST_FLAG_START_IN_TRI;
|
||||
}
|
||||
}
|
||||
} // if (result == 0.0f)
|
||||
} // else (result < 0.0f)
|
||||
} // if Point_In_Triangle_2D()
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
173
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/v3_rnd.cpp
Normal file
173
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/v3_rnd.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 : G *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/wwmath/v3_rnd.cpp $*
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 7/09/99 9:49a $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "v3_rnd.h"
|
||||
#include "vector2.h"
|
||||
|
||||
const float Vector3Randomizer::OOIntMax = 1.0f / (float)INT_MAX;
|
||||
const float Vector3Randomizer::OOUIntMax = 1.0f / (float)UINT_MAX;
|
||||
Random3Class Vector3Randomizer::Randomizer;
|
||||
|
||||
Vector3SolidBoxRandomizer::Vector3SolidBoxRandomizer(const Vector3 & extents)
|
||||
{
|
||||
Extents.X = MAX(extents.X, 0.0f);
|
||||
Extents.Y = MAX(extents.Y, 0.0f);
|
||||
Extents.Z = MAX(extents.Z, 0.0f);
|
||||
}
|
||||
|
||||
void Vector3SolidBoxRandomizer::Get_Vector(Vector3 &vector)
|
||||
{
|
||||
vector.X = Get_Random_Float_Minus1_To_1() * Extents.X;
|
||||
vector.Y = Get_Random_Float_Minus1_To_1() * Extents.Y;
|
||||
vector.Z = Get_Random_Float_Minus1_To_1() * Extents.Z;
|
||||
}
|
||||
|
||||
float Vector3SolidBoxRandomizer::Get_Maximum_Extent(void)
|
||||
{
|
||||
float max = MAX(Extents.X, Extents.Y);
|
||||
max = MAX(max, Extents.Z);
|
||||
return max;
|
||||
}
|
||||
|
||||
void Vector3SolidBoxRandomizer::Scale(float scale)
|
||||
{
|
||||
scale = MAX(scale, 0.0f);
|
||||
Extents.X *= scale;
|
||||
Extents.Y *= scale;
|
||||
Extents.Z *= scale;
|
||||
}
|
||||
|
||||
|
||||
Vector3SolidSphereRandomizer::Vector3SolidSphereRandomizer(float radius)
|
||||
{
|
||||
Radius = MAX(radius, 0.0f);
|
||||
}
|
||||
|
||||
void Vector3SolidSphereRandomizer::Get_Vector(Vector3 &vector)
|
||||
{
|
||||
// Generate vectors in a cube and discard the ones not in a sphere
|
||||
float rad_squared = Radius * Radius;
|
||||
for (;;) {
|
||||
vector.X = Get_Random_Float_Minus1_To_1() * Radius;
|
||||
vector.Y = Get_Random_Float_Minus1_To_1() * Radius;
|
||||
vector.Z = Get_Random_Float_Minus1_To_1() * Radius;
|
||||
if (vector.Length2() <= rad_squared) break;
|
||||
}
|
||||
}
|
||||
|
||||
float Vector3SolidSphereRandomizer::Get_Maximum_Extent(void)
|
||||
{
|
||||
return Radius;
|
||||
}
|
||||
|
||||
void Vector3SolidSphereRandomizer::Scale(float scale)
|
||||
{
|
||||
scale = MAX(scale, 0.0f);
|
||||
Radius *= scale;
|
||||
}
|
||||
|
||||
|
||||
Vector3HollowSphereRandomizer::Vector3HollowSphereRandomizer(float radius)
|
||||
{
|
||||
Radius = MAX(radius, 0.0f);
|
||||
}
|
||||
|
||||
void Vector3HollowSphereRandomizer::Get_Vector(Vector3 &vector)
|
||||
{
|
||||
// Generate vectors in a 2x2x2 origin-centered cube, discard the ones not in a unit-radius
|
||||
// sphere and scale the result to Radius.
|
||||
float v_l2;
|
||||
for (;;) {
|
||||
vector.X = Get_Random_Float_Minus1_To_1();
|
||||
vector.Y = Get_Random_Float_Minus1_To_1();
|
||||
vector.Z = Get_Random_Float_Minus1_To_1();
|
||||
v_l2 = vector.Length2();
|
||||
if (v_l2 <= 1.0f && v_l2 > 0.0f) break;
|
||||
}
|
||||
|
||||
float scale = Radius * WWMath::Inv_Sqrt(v_l2);
|
||||
|
||||
vector.X *= scale;
|
||||
vector.Y *= scale;
|
||||
vector.Z *= scale;
|
||||
}
|
||||
|
||||
float Vector3HollowSphereRandomizer::Get_Maximum_Extent(void)
|
||||
{
|
||||
return Radius;
|
||||
}
|
||||
|
||||
void Vector3HollowSphereRandomizer::Scale(float scale)
|
||||
{
|
||||
scale = MAX(scale, 0.0f);
|
||||
Radius *= scale;
|
||||
}
|
||||
|
||||
|
||||
Vector3SolidCylinderRandomizer::Vector3SolidCylinderRandomizer(float extent, float radius)
|
||||
{
|
||||
Extent = MAX(extent, 0.0f);
|
||||
Radius = MAX(radius, 0.0f);
|
||||
}
|
||||
|
||||
void Vector3SolidCylinderRandomizer::Get_Vector(Vector3 &vector)
|
||||
{
|
||||
vector.X = Get_Random_Float_Minus1_To_1() * Extent;
|
||||
|
||||
// Generate 2D vectors in a square and discard the ones not in a circle
|
||||
Vector2 vec2;
|
||||
float rad_squared = Radius * Radius;
|
||||
for (;;) {
|
||||
vec2.X = Get_Random_Float_Minus1_To_1() * Radius;
|
||||
vec2.Y = Get_Random_Float_Minus1_To_1() * Radius;
|
||||
if (vec2.Length2() <= rad_squared) break;
|
||||
}
|
||||
|
||||
vector.Y = vec2.X;
|
||||
vector.Z = vec2.Y;
|
||||
}
|
||||
|
||||
float Vector3SolidCylinderRandomizer::Get_Maximum_Extent(void)
|
||||
{
|
||||
return MAX(Extent, Radius);
|
||||
}
|
||||
|
||||
void Vector3SolidCylinderRandomizer::Scale(float scale)
|
||||
{
|
||||
scale = MAX(scale, 0.0f);
|
||||
Extent *= scale;
|
||||
Radius *= scale;
|
||||
}
|
||||
235
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/v3_rnd.h
Normal file
235
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/v3_rnd.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 : G *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/wwmath/v3_rnd.h $*
|
||||
* *
|
||||
* $Author:: Greg_h $*
|
||||
* *
|
||||
* $Modtime:: 7/09/99 9:49a $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef V3_RND_H
|
||||
#define V3_RND_H
|
||||
|
||||
#include "always.h"
|
||||
#include "vector3.h"
|
||||
#include "random.h"
|
||||
#include <limits.h>
|
||||
|
||||
/*
|
||||
** Vector3Randomizer is an abstract class for generating random Vector3s.
|
||||
** Examples: generating vectors in a sphere, cylinder, etc.
|
||||
** This file contains several concrete derived classes; others may be defined
|
||||
** in future.
|
||||
** A possible future extension to this class would be to add a method to
|
||||
** efficiently get an array of random points.
|
||||
*/
|
||||
|
||||
class Vector3Randomizer {
|
||||
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
CLASSID_UNKNOWN = 0xFFFFFFFF,
|
||||
CLASSID_SOLIDBOX = 0,
|
||||
CLASSID_SOLIDSPHERE,
|
||||
CLASSID_HOLLOWSPHERE,
|
||||
CLASSID_SOLIDCYLINDER,
|
||||
CLASSID_MAXKNOWN,
|
||||
CLASSID_LAST = 0x0000FFFF
|
||||
};
|
||||
|
||||
virtual ~Vector3Randomizer(void) { }
|
||||
|
||||
// RTTI identifiction
|
||||
virtual unsigned int Class_ID (void) const = 0;
|
||||
|
||||
// Return a random vector
|
||||
virtual void Get_Vector(Vector3 &vector) = 0;
|
||||
|
||||
// Get the maximum component possible for generated vectors
|
||||
virtual float Get_Maximum_Extent(void) = 0;
|
||||
|
||||
// Scale all vectors produced in future
|
||||
virtual void Scale(float scale) = 0;
|
||||
|
||||
// Clone the randomizer
|
||||
virtual Vector3Randomizer * Clone(void) const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
// Derived classes should have protected copy CTors so users use the Clone() function
|
||||
|
||||
// Utility functions
|
||||
float Get_Random_Float_Minus1_To_1() { return Randomizer * OOIntMax; }
|
||||
float Get_Random_Float_0_To_1() { return ((unsigned int)Randomizer) * OOUIntMax; }
|
||||
|
||||
static const float OOIntMax;
|
||||
static const float OOUIntMax;
|
||||
static Random3Class Randomizer;
|
||||
|
||||
private:
|
||||
|
||||
// Derived classes should have a private dummy assignment operator to block usage
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Vector3SolidBoxRandomizer is a randomizer for generating points uniformly distributed inside a
|
||||
** box which is centered on the origin.
|
||||
*/
|
||||
class Vector3SolidBoxRandomizer : public Vector3Randomizer {
|
||||
|
||||
public:
|
||||
|
||||
Vector3SolidBoxRandomizer(const Vector3 & extents);
|
||||
|
||||
virtual unsigned int Class_ID (void) const { return CLASSID_SOLIDBOX; }
|
||||
virtual const Vector3 & Get_Extents (void) const { return Extents; }
|
||||
virtual void Get_Vector(Vector3 &vector);
|
||||
virtual float Get_Maximum_Extent(void);
|
||||
virtual void Scale(float scale);
|
||||
virtual Vector3Randomizer * Clone(void) const { return W3DNEW Vector3SolidBoxRandomizer(*this); }
|
||||
|
||||
protected:
|
||||
|
||||
// Derived classes should have protected copy CTors so users use the Clone() function
|
||||
Vector3SolidBoxRandomizer(const Vector3SolidBoxRandomizer &src) : Extents(src.Extents) { }
|
||||
|
||||
private:
|
||||
|
||||
// Derived classes should have a private dummy assignment operator to block usage
|
||||
Vector3SolidBoxRandomizer & Vector3SolidBoxRandomizer::operator = (const Vector3SolidBoxRandomizer &that) { that; return *this; }
|
||||
|
||||
Vector3 Extents;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Vector3SolidSphereRandomizer is a randomizer for generating points uniformly distributed inside
|
||||
** a sphere which is centered on the origin.
|
||||
*/
|
||||
class Vector3SolidSphereRandomizer : public Vector3Randomizer {
|
||||
|
||||
public:
|
||||
|
||||
Vector3SolidSphereRandomizer(float radius);
|
||||
|
||||
virtual unsigned int Class_ID (void) const { return CLASSID_SOLIDSPHERE; }
|
||||
virtual float Get_Radius (void) const { return Radius; }
|
||||
virtual void Get_Vector(Vector3 &vector);
|
||||
virtual float Get_Maximum_Extent(void);
|
||||
virtual void Scale(float scale);
|
||||
virtual Vector3Randomizer * Clone(void) const { return W3DNEW Vector3SolidSphereRandomizer(*this); }
|
||||
|
||||
protected:
|
||||
|
||||
// Derived classes should have protected copy CTors so users use the Clone() function
|
||||
Vector3SolidSphereRandomizer(const Vector3SolidSphereRandomizer &src) : Radius(src.Radius) { }
|
||||
|
||||
private:
|
||||
|
||||
// Derived classes should have a private dummy assignment operator to block usage
|
||||
Vector3SolidSphereRandomizer & Vector3SolidSphereRandomizer::operator = (const Vector3SolidSphereRandomizer &that) { that; return *this; }
|
||||
|
||||
float Radius;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Vector3HollowSphereRandomizer is a randomizer for generating points uniformly distributed on the
|
||||
** surface of a sphere which is centered on the origin.
|
||||
*/
|
||||
class Vector3HollowSphereRandomizer : public Vector3Randomizer {
|
||||
|
||||
public:
|
||||
|
||||
Vector3HollowSphereRandomizer(float radius);
|
||||
|
||||
virtual unsigned int Class_ID (void) const { return CLASSID_HOLLOWSPHERE; }
|
||||
virtual float Get_Radius (void) const { return Radius; }
|
||||
virtual void Get_Vector(Vector3 &vector);
|
||||
virtual float Get_Maximum_Extent(void);
|
||||
virtual void Scale(float scale);
|
||||
virtual Vector3Randomizer * Clone(void) const { return W3DNEW Vector3HollowSphereRandomizer(*this); }
|
||||
|
||||
protected:
|
||||
|
||||
// Derived classes should have protected copy CTors so users use the Clone() function
|
||||
Vector3HollowSphereRandomizer(const Vector3HollowSphereRandomizer &src) : Radius(src.Radius) { }
|
||||
|
||||
private:
|
||||
|
||||
// Derived classes should have a private dummy assignment operator to block usage
|
||||
Vector3HollowSphereRandomizer & Vector3HollowSphereRandomizer::operator = (const Vector3HollowSphereRandomizer &that) { that; return *this; }
|
||||
|
||||
float Radius;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Vector3SolidCylinderRandomizer is a randomizer for generating points uniformly distributed
|
||||
** inside a cylinder which is centered on the origin (set extent to 0 for a disk).
|
||||
*/
|
||||
class Vector3SolidCylinderRandomizer : public Vector3Randomizer {
|
||||
|
||||
public:
|
||||
|
||||
Vector3SolidCylinderRandomizer(float extent, float radius);
|
||||
|
||||
virtual unsigned int Class_ID (void) const { return CLASSID_SOLIDCYLINDER; }
|
||||
virtual float Get_Radius (void) const { return Radius; }
|
||||
virtual float Get_Height (void) const { return Extent; }
|
||||
virtual void Get_Vector(Vector3 &vector);
|
||||
virtual float Get_Maximum_Extent(void);
|
||||
virtual void Scale(float scale);
|
||||
virtual Vector3Randomizer * Clone(void) const { return W3DNEW Vector3SolidCylinderRandomizer(*this); }
|
||||
|
||||
protected:
|
||||
|
||||
// Derived classes should have protected copy CTors so users use the Clone() function
|
||||
Vector3SolidCylinderRandomizer(const Vector3SolidCylinderRandomizer &src) : Extent(src.Extent), Radius(src.Radius) { }
|
||||
|
||||
private:
|
||||
|
||||
// Derived classes should have a private dummy assignment operator to block usage
|
||||
Vector3SolidCylinderRandomizer & Vector3SolidCylinderRandomizer::operator = (const Vector3SolidCylinderRandomizer &that) { that; return *this; }
|
||||
|
||||
float Extent;
|
||||
float Radius;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
671
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vector2.h
Normal file
671
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vector2.h
Normal file
@@ -0,0 +1,671 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/vector2.h 24 7/06/01 9:43a Byon_g $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood 3D *
|
||||
* *
|
||||
* File Name : VECTOR2.H *
|
||||
* *
|
||||
* Programmer : Greg Hjelstrom *
|
||||
* *
|
||||
* Start Date : 02/24/97 *
|
||||
* *
|
||||
* Last Update : February 24, 1997 [GH] *
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Scalar Division Operator -- Divide a vector by a scalar *
|
||||
* Scalar Multiply Operator -- Multiply a vector by a scalar *
|
||||
* Vector Addition Operator -- Add two vectors *
|
||||
* Vector Subtraction Operator -- Subract two vectors *
|
||||
* Vector Inner Product Operator -- Compute the inner or dot product *
|
||||
* Vector Equality Operator -- Detemine if two vectors are identical *
|
||||
* Equal_Within_Epsilon -- Determine if two vectors are identical within *
|
||||
* Vector Inequality Operator -- Detemine if two vectors are identical *
|
||||
* Swap -- swap two Vector2's *
|
||||
* Vector2::Is_Valid -- Verifies that all components are valid floats *
|
||||
* Vector2::Update_Min -- sets each component of the vector to the min of this and a. *
|
||||
* Vector2::Update_Max -- sets each component of the vector to the max of this and a. *
|
||||
* Vector2::Scale -- multiply components of a vector by independant scaling factors. *
|
||||
* Vector2::Lerp -- linearly interpolates two Vector2's *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef VECTOR2_H
|
||||
#define VECTOR2_H
|
||||
|
||||
#include "always.h"
|
||||
#include "wwmath.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
/*
|
||||
** 2-Dimensional Vectors
|
||||
*/
|
||||
|
||||
class Vector2
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
union {
|
||||
float X;
|
||||
float U;
|
||||
};
|
||||
|
||||
union {
|
||||
float Y;
|
||||
float V;
|
||||
};
|
||||
|
||||
// Constructors
|
||||
WWINLINE Vector2(void) {};
|
||||
WWINLINE Vector2(const Vector2 & v) { X = v.X; Y = v.Y; }
|
||||
WWINLINE Vector2(float x, float y) { X = x; Y = y; }
|
||||
WWINLINE Vector2(const float vector[2]) { X = vector[0]; Y = vector[1]; }
|
||||
|
||||
|
||||
// Assignment
|
||||
WWINLINE Vector2 & operator = (const Vector2 & v) { X = v[0]; Y = v[1]; return *this; }
|
||||
WWINLINE void Set(float x, float y) { X = x; Y = y; }
|
||||
WWINLINE void Set(const Vector2 & v) { X = v.X; Y = v.Y; }
|
||||
|
||||
// Array access
|
||||
WWINLINE float & operator [](int i) { return (&X)[i]; }
|
||||
WWINLINE const float & operator [](int i) const { return (&X)[i]; }
|
||||
|
||||
// normalize, compute length
|
||||
WWINLINE void Normalize(void);
|
||||
WWINLINE float Length(void) const;
|
||||
WWINLINE float Length2(void) const;
|
||||
|
||||
// unary operators
|
||||
WWINLINE Vector2 operator-() const { return Vector2(-X,-Y); }
|
||||
WWINLINE Vector2 operator+() const { return *this; }
|
||||
|
||||
WWINLINE Vector2 & operator += (const Vector2 & v) { X += v.X; Y += v.Y; return *this; }
|
||||
WWINLINE Vector2 & operator -= (const Vector2 & v) { X -= v.X; Y -= v.Y; return *this; }
|
||||
WWINLINE Vector2 & operator *= (float k) { X = (float)(X*k); Y=(float)(Y*k); return *this; }
|
||||
WWINLINE Vector2 & operator /= (float k) { k=1.0f/k; X*=k; Y*=k; return *this; }
|
||||
|
||||
// scalar multiplication, division
|
||||
WWINLINE friend Vector2 operator * (const Vector2 &a,float k);
|
||||
WWINLINE friend Vector2 operator * (float k,const Vector2 &a);
|
||||
WWINLINE friend Vector2 operator / (const Vector2 &a,float k);
|
||||
|
||||
// vector addition,subtraction
|
||||
WWINLINE friend Vector2 operator + (const Vector2 &a,const Vector2 &b);
|
||||
WWINLINE friend Vector2 operator - (const Vector2 &a,const Vector2 &b);
|
||||
|
||||
// dot product / inner product
|
||||
WWINLINE friend float operator * (const Vector2 &a,const Vector2 &b);
|
||||
static WWINLINE float Dot_Product(const Vector2 &a,const Vector2 &b);
|
||||
|
||||
// dot product between a and perpendicular vector to b
|
||||
static float Perp_Dot_Product(const Vector2 &a,const Vector2 &b);
|
||||
|
||||
// Equality operators
|
||||
friend bool operator == (const Vector2 &a,const Vector2 &b);
|
||||
friend bool operator != (const Vector2 &a,const Vector2 &b);
|
||||
WWINLINE friend bool Equal_Within_Epsilon(const Vector2 &a,const Vector2 &b,float epsilon);
|
||||
|
||||
// Rotation
|
||||
WWINLINE void Rotate(float theta);
|
||||
WWINLINE void Rotate(float s, float c);
|
||||
WWINLINE bool Rotate_Towards_Vector(Vector2 &target, float max_theta, bool & positive_turn);
|
||||
WWINLINE bool Rotate_Towards_Vector(Vector2 &target, float max_s, float max_c, bool & positive_turn);
|
||||
|
||||
// verify that none of the members of this vector are invalid floats
|
||||
WWINLINE bool Is_Valid(void) const;
|
||||
|
||||
// make this vector the min or max of itself and the passed vector
|
||||
WWINLINE void Update_Min (const Vector2 & a);
|
||||
WWINLINE void Update_Max (const Vector2 & a);
|
||||
WWINLINE void Scale (float a, float b);
|
||||
WWINLINE void Scale (const Vector2 & a);
|
||||
|
||||
static WWINLINE float Distance(const Vector2 &p1, const Vector2 &p2);
|
||||
static WWINLINE float Quick_Distance(const Vector2 &p1, const Vector2 &p2);
|
||||
|
||||
// interpolate between two Vector2's
|
||||
static void Lerp(const Vector2 & a,const Vector2 & b,float t,Vector2 * set_result);
|
||||
};
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Scalar Multiply Operator -- Multiply a vector by a scalar *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector2 operator * (const Vector2 &a,float k)
|
||||
{
|
||||
float a0k(a[0] * k);
|
||||
float a1k(a[1] * k);
|
||||
return Vector2(a0k,a1k);
|
||||
}
|
||||
|
||||
WWINLINE Vector2 operator * (float k, const Vector2 &a)
|
||||
{
|
||||
float a0k(a[0] * k);
|
||||
float a1k(a[1] * k);
|
||||
return Vector2(a0k,a1k);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Scalar Division Operator -- Divide a vector by a scalar *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector2 operator / (const Vector2 &a,float k)
|
||||
{
|
||||
float ook=1.0f/k;
|
||||
float a0ook(a[0] * ook);
|
||||
float a1ook(a[1] * ook);
|
||||
return Vector2(a0ook,a1ook);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Addition Operator -- Add two vectors *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector2 operator + (const Vector2 &a,const Vector2 &b)
|
||||
{
|
||||
return Vector2(
|
||||
a.X + b.X,
|
||||
a.Y + b.Y
|
||||
);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Subtraction Operator -- Subract two vectors *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector2 operator - (const Vector2 &a,const Vector2 &b)
|
||||
{
|
||||
return Vector2(
|
||||
a.X - b.X,
|
||||
a.Y - b.Y
|
||||
);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Inner Product -- Compute the inner or dot product of two vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE float operator * (const Vector2 &a,const Vector2 &b)
|
||||
{
|
||||
return a.X*b.X + a.Y*b.Y;
|
||||
}
|
||||
|
||||
WWINLINE float Vector2::Dot_Product(const Vector2 &a,const Vector2 &b)
|
||||
{
|
||||
return a*b;
|
||||
}
|
||||
|
||||
WWINLINE float Vector2::Perp_Dot_Product(const Vector2 &a,const Vector2 &b)
|
||||
{
|
||||
return a.X * -b.Y + a.Y * b.X;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Equality Operator -- Detemine if two vectors are identical *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool operator == (const Vector2 &a,const Vector2 &b)
|
||||
{
|
||||
bool a0b0(a[0] == b[0]);
|
||||
bool a1b1(a[1] == b[1]);
|
||||
return ( a0b0 & a1b1);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Inequality Operator -- Detemine if two vectors are identical *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool operator != (const Vector2 &a,const Vector2 &b)
|
||||
{
|
||||
bool a0b0(a[0] != b[0]);
|
||||
bool a1b1(a[1] != b[1]);
|
||||
return ( a0b0 | a1b1);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Equal_Within_Epsilon -- Determine if two vectors are identical within e*
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool Equal_Within_Epsilon(const Vector2 &a,const Vector2 &b,float epsilon)
|
||||
{
|
||||
return( (WWMath::Fabs(a.X - b.X) < epsilon) && (WWMath::Fabs(a.Y - b.Y) < epsilon) );
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector2::Normalize -- Normalizes the vector. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE void Vector2::Normalize()
|
||||
{
|
||||
float len2 = Length2();
|
||||
if (len2 != 0.0f) {
|
||||
float oolen = WWMath::Inv_Sqrt(len2);
|
||||
X *= oolen;
|
||||
Y *= oolen;
|
||||
}
|
||||
}
|
||||
|
||||
WWINLINE Vector2 Normalize(const Vector2 & vec)
|
||||
{
|
||||
float len2 = vec.Length2();
|
||||
if (len2 != 0.0f) {
|
||||
float oolen = WWMath::Inv_Sqrt(len2);
|
||||
return vec / oolen;
|
||||
}
|
||||
return Vector2(0.0f,0.0f);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector2::Length -- Returns the length of the vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE float Vector2::Length() const
|
||||
{
|
||||
return (float)WWMath::Sqrt(Length2());
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector2::Length -- Returns the square of the length of the vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE float Vector2::Length2() const
|
||||
{
|
||||
return (X*X + Y*Y);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector2::Rotate -- Rotate vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* float theta - angle to rotate *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE void Vector2::Rotate(float theta)
|
||||
{
|
||||
Rotate(WWMath::Sin(theta), WWMath::Cos(theta));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector2::Rotate -- Rotate vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* s - sine of the angle *
|
||||
* c - cosine of the angle *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE void Vector2::Rotate(float s, float c)
|
||||
{
|
||||
float new_x = X * c + Y * -s;
|
||||
float new_y = X * s + Y * c;
|
||||
X = new_x;
|
||||
Y = new_y;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector2::Rotate -- Rotate towards given vector (stop on reaching it) *
|
||||
* *
|
||||
* INPUT: *
|
||||
* float theta - angle to rotate *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* bool - true if we have reached the desired vector *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* This function assumes both vectors are normalized! *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool Vector2::Rotate_Towards_Vector(Vector2 &target, float max_theta, bool & positive_turn)
|
||||
{
|
||||
return Rotate_Towards_Vector(target, WWMath::Sin(max_theta), WWMath::Cos(max_theta), positive_turn);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector2::Rotate -- Rotate towards given vector (stop on reaching it) *
|
||||
* *
|
||||
* INPUT: *
|
||||
* s - sine of the angle *
|
||||
* c - cosine of the angle *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* bool - true if we have reached the desired vector *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* This function assumes both vectors are normalized! *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool Vector2::Rotate_Towards_Vector(Vector2 &target, float max_s, float max_c, bool & positive_turn)
|
||||
{
|
||||
bool return_value = false;
|
||||
|
||||
positive_turn = Vector2::Perp_Dot_Product(target, *this) > 0.0f;
|
||||
|
||||
if (Vector2::Dot_Product(*this, target) >= max_c) {
|
||||
Set(target);
|
||||
return_value = true;
|
||||
} else {
|
||||
// Determine turn direction and rotate accordingly.
|
||||
if (positive_turn) {
|
||||
Rotate(max_s, max_c);
|
||||
} else {
|
||||
Rotate(-max_s, max_c);
|
||||
}
|
||||
}
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Swap -- swap two Vector2's *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Swap(Vector2 & a,Vector2 & b)
|
||||
{
|
||||
Vector2 tmp(a);
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector2::Is_Valid -- Verifies that all components are valid floats *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE bool Vector2::Is_Valid(void) const
|
||||
{
|
||||
return (WWMath::Is_Valid_Float(X) && WWMath::Is_Valid_Float(Y));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector2::Update_Min -- Set each component of the vector to the min of this and a. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/12/00 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector2::Update_Min (const Vector2 & a)
|
||||
{
|
||||
if (a.X < X) X = a.X;
|
||||
if (a.Y < Y) Y = a.Y;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector2::Update_Max -- Set each component of the vector to the max of this and a. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/12/00 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector2::Update_Max (const Vector2 & a)
|
||||
{
|
||||
if (a.X > X) X = a.X;
|
||||
if (a.Y > Y) Y = a.Y;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector2::Scale -- multiply components of a vector by independant scaling factors. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/19/2000 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector2::Scale (float a, float b)
|
||||
{
|
||||
X *= a;
|
||||
Y *= b;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector2::Scale -- multiply components of a vector by independant scaling factors. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/19/2000 IML : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector2::Scale (const Vector2 & a)
|
||||
{
|
||||
X *= a.X;
|
||||
Y *= a.Y;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Quick_Distance -- Fast but inaccurate 2D distance calculation. *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/29/1999MLL: Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE float Quick_Distance(float x1, float y1, float x2, float y2)
|
||||
{
|
||||
// From Graphic Gems I.
|
||||
float x_diff = x1 - x2;
|
||||
float y_diff = y1 - y2;
|
||||
|
||||
WWMath::Fabs(x_diff);
|
||||
WWMath::Fabs(y_diff);
|
||||
|
||||
if (x_diff > y_diff)
|
||||
{
|
||||
return ((y_diff / 2) + x_diff);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((x_diff / 2) + y_diff);
|
||||
}
|
||||
}
|
||||
|
||||
WWINLINE float Vector2::Quick_Distance(const Vector2 &a, const Vector2 &b)
|
||||
{
|
||||
return ::Quick_Distance(a.X, a.Y, b.X, b.Y);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Distance -- Accurate distance 2D calculation. *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/29/1999MLL: Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE float Vector2::Distance(const Vector2 &a, const Vector2 &b)
|
||||
{
|
||||
Vector2 temp;
|
||||
temp = a - b;
|
||||
|
||||
return (temp.Length());
|
||||
}
|
||||
|
||||
WWINLINE float Distance(float x1, float y1, float x2, float y2)
|
||||
{
|
||||
float x_diff = x1 - x2;
|
||||
float y_diff = y1 - y2;
|
||||
|
||||
return (WWMath::Sqrt((x_diff * x_diff) + (y_diff * y_diff)));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector2::Lerp -- linearly interpolates two Vector2's *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 4/14/2000 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector2::Lerp(const Vector2 & a,const Vector2 & b,float t,Vector2 * set_result)
|
||||
{
|
||||
assert(set_result != NULL);
|
||||
set_result->X = (a.X + (b.X - a.X)*t);
|
||||
set_result->Y = (a.Y + (b.Y - a.Y)*t);
|
||||
}
|
||||
|
||||
|
||||
#endif /* VECTOR2_H */
|
||||
|
||||
113
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vector2i.h
Normal file
113
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vector2i.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/vector2i.h $*
|
||||
* *
|
||||
* Author:: Eric Cosky *
|
||||
* *
|
||||
* $Modtime:: 5/10/01 11:37p $*
|
||||
* *
|
||||
* $Revision:: 4 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef VECTOR2I_H
|
||||
#define VECTOR2I_H
|
||||
|
||||
#include "always.h"
|
||||
|
||||
class Vector2i
|
||||
{
|
||||
public:
|
||||
|
||||
int I;
|
||||
int J;
|
||||
|
||||
WWINLINE Vector2i(void);
|
||||
WWINLINE Vector2i(int i,int j);
|
||||
|
||||
WWINLINE void Set(int i, int j);
|
||||
|
||||
WWINLINE void Swap(Vector2i & other);
|
||||
|
||||
WWINLINE bool operator== (const Vector2i & v) const;
|
||||
WWINLINE bool operator!= (const Vector2i& v) const;
|
||||
WWINLINE const int& operator[] (int n) const;
|
||||
WWINLINE int& operator[] (int n);
|
||||
};
|
||||
|
||||
|
||||
WWINLINE Vector2i::Vector2i(void)
|
||||
{
|
||||
}
|
||||
|
||||
WWINLINE Vector2i::Vector2i(int i,int j)
|
||||
{
|
||||
I = i; J = j;
|
||||
}
|
||||
|
||||
WWINLINE bool Vector2i::operator == (const Vector2i & v) const
|
||||
{
|
||||
return (I == v.I && J == v.J );
|
||||
}
|
||||
|
||||
WWINLINE bool Vector2i::operator != (const Vector2i& v) const
|
||||
{
|
||||
return !(I == v.I && J == v.J);
|
||||
}
|
||||
|
||||
WWINLINE const int& Vector2i::operator[] (int n) const
|
||||
{
|
||||
return ((int*)this)[n];
|
||||
}
|
||||
|
||||
WWINLINE int& Vector2i::operator[] (int n)
|
||||
{
|
||||
return ((int*)this)[n];
|
||||
}
|
||||
|
||||
WWINLINE void Vector2i::Set(int i, int j) { I = i; J = j; }
|
||||
|
||||
WWINLINE void Vector2i::Swap(Vector2i & other)
|
||||
{
|
||||
// this could use MMX..
|
||||
|
||||
I ^= other.I;
|
||||
other.I ^= I;
|
||||
I ^= other.I;
|
||||
|
||||
J ^= other.J;
|
||||
other.J ^= J;
|
||||
J ^= other.J;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
916
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vector3.h
Normal file
916
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vector3.h
Normal file
@@ -0,0 +1,916 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/vector3.h 40 5/11/01 7:11p Jani_p $ */
|
||||
/***********************************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood 3D *
|
||||
* *
|
||||
* File Name : VECTOR3.H *
|
||||
* *
|
||||
* Programmer : Greg Hjelstrom *
|
||||
* *
|
||||
* Start Date : 02/24/97 *
|
||||
* *
|
||||
* Last Update : February 24, 1997 [GH] *
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Scalar Division Operator -- Divide a vector by a scalar *
|
||||
* Scalar Multiply Operator -- Multiply a vector by a scalar *
|
||||
* Vector Addition Operator -- Add two vectors *
|
||||
* Vector Subtraction Operator -- Subract two vectors *
|
||||
* Vector Inner Product Operator -- Compute the inner or dot product *
|
||||
* Vector Equality Operator -- Determine if two vectors are identical *
|
||||
* Vector Inequality Operator -- Determine if two vectors are identical *
|
||||
* Equal_Within_Epsilon -- Determine if two vectors are identical within *
|
||||
* Cross_Product -- compute the cross product of two vectors *
|
||||
* Vector3::Normalize -- Normalizes the vector. *
|
||||
* Vector3::Length -- Returns the length of the vector *
|
||||
* Vector3::Length2 -- Returns the square of the length of the vector *
|
||||
* Vector3::Quick_Length -- returns a quick approximation of the length *
|
||||
* Swap -- swap two Vector3's *
|
||||
* Lerp -- linearly interpolate two Vector3's by an interpolation factor. *
|
||||
* Lerp -- linearly interpolate two Vector3's without return-by-value *
|
||||
* Vector3::Add -- Add two vector3's without return-by-value *
|
||||
* Vector3::Subtract -- Subtract two vector3's without return-by-value *
|
||||
* Vector3::Update_Min -- sets each component of the vector to the min of this and a *
|
||||
* Vector3::Update_Max -- Sets each component of the vector to the max of this and a *
|
||||
* Vector3::Scale -- scale this vector by 3 independent scale factors *
|
||||
* Vector3::Rotate_X -- rotates this vector around the X axis *
|
||||
* Vector3::Rotate_X -- Rotates this vector around the x axis *
|
||||
* Vector3::Rotate_Y -- Rotates this vector around the y axis *
|
||||
* Vector3::Rotate_Y -- Rotates this vector around the Y axis *
|
||||
* Vector3::Rotate_Z -- Rotates this vector around the Z axis *
|
||||
* Vector3::Rotate_Z -- Rotates this vector around the Z axis *
|
||||
* Vector3::Is_Valid -- Verifies that each component of this vector is a valid float *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef VECTOR3_H
|
||||
#define VECTOR3_H
|
||||
|
||||
#include "always.h"
|
||||
#include "wwmath.h"
|
||||
#include <assert.h>
|
||||
#ifdef _UNIX
|
||||
#include "osdep.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Vector3 - 3-Dimensional Vectors
|
||||
*/
|
||||
class Vector3
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
|
||||
float X;
|
||||
float Y;
|
||||
float Z;
|
||||
|
||||
|
||||
// Constructors
|
||||
WWINLINE Vector3(void) {};
|
||||
WWINLINE Vector3(const Vector3 & v) { X = v.X; Y = v.Y; Z = v.Z; }
|
||||
WWINLINE Vector3(float x, float y, float z) { X = x; Y = y; Z = z; }
|
||||
WWINLINE Vector3(const float vector[3]) { X = vector[0]; Y = vector[1]; Z = vector[2]; }
|
||||
|
||||
// Assignment
|
||||
WWINLINE Vector3 & operator = (const Vector3 & v) { X = v.X; Y = v.Y; Z = v.Z; return *this; }
|
||||
WWINLINE void Set(float x, float y, float z) { X = x; Y = y; Z = z; }
|
||||
WWINLINE void Set(const Vector3 & that) { X = that.X; Y = that.Y; Z = that.Z; }
|
||||
|
||||
// Array access
|
||||
WWINLINE float & operator [](int i) { return (&X)[i]; }
|
||||
WWINLINE const float & operator [](int i) const { return (&X)[i]; }
|
||||
|
||||
// normalize, compute length
|
||||
void Normalize(void);
|
||||
WWINLINE float Length(void) const;
|
||||
WWINLINE float Length2(void) const;
|
||||
float Quick_Length(void) const;
|
||||
void Scale(const Vector3 & scale);
|
||||
|
||||
// rotation, (warning, modifies this vector!)
|
||||
WWINLINE void Rotate_X(float angle);
|
||||
WWINLINE void Rotate_X(float s_angle,float c_angle);
|
||||
WWINLINE void Rotate_Y(float angle);
|
||||
WWINLINE void Rotate_Y(float s_angle,float c_angle);
|
||||
WWINLINE void Rotate_Z(float angle);
|
||||
WWINLINE void Rotate_Z(float s_angle,float c_angle);
|
||||
|
||||
// unary operators
|
||||
WWINLINE Vector3 operator-() const { return(Vector3(-X,-Y,-Z)); }
|
||||
WWINLINE Vector3 operator+() const { return *this; }
|
||||
|
||||
WWINLINE Vector3 & operator += (const Vector3 & v) { X += v.X; Y += v.Y; Z += v.Z; return *this; }
|
||||
WWINLINE Vector3 & operator -= (const Vector3 & v) { X -= v.X; Y -= v.Y; Z -= v.Z; return *this; }
|
||||
WWINLINE Vector3 & operator *= (float k) { X = X*k; Y=Y*k; Z=Z*k; return *this; }
|
||||
WWINLINE Vector3 & operator /= (float k) { float ook=1.0f/k; X=X*ook; Y=Y*ook; Z=Z*ook; return *this; }
|
||||
|
||||
// scalar multiplication, division
|
||||
WWINLINE friend Vector3 operator * (const Vector3 &a,float k);
|
||||
WWINLINE friend Vector3 operator * (float k,const Vector3 &a);
|
||||
WWINLINE friend Vector3 operator / (const Vector3 &a,float k);
|
||||
|
||||
// vector addition,subtraction
|
||||
WWINLINE friend Vector3 operator + (const Vector3 &a,const Vector3 &b);
|
||||
WWINLINE friend Vector3 operator - (const Vector3 &a,const Vector3 &b);
|
||||
|
||||
// Equality operators
|
||||
friend bool operator == (const Vector3 &a,const Vector3 &b);
|
||||
friend bool operator != (const Vector3 &a,const Vector3 &b);
|
||||
WWINLINE friend bool Equal_Within_Epsilon(const Vector3 &a,const Vector3 &b,float epsilon);
|
||||
|
||||
// dot product / inner product
|
||||
//WWINLINE friend float operator * (const Vector3 &a,const Vector3 &b);
|
||||
static WWINLINE float Dot_Product(const Vector3 &a,const Vector3 &b);
|
||||
|
||||
// cross product / outer product
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
static WWINLINE Vector3 Cross_Product(const Vector3 &a,const Vector3 &b);
|
||||
#endif
|
||||
static WWINLINE void Cross_Product(const Vector3 &a,const Vector3 &b,Vector3 * result);
|
||||
static WWINLINE void Normalized_Cross_Product(const Vector3 &a, const Vector3 &b, Vector3 * result);
|
||||
static WWINLINE float Cross_Product_X(const Vector3 &a,const Vector3 &b);
|
||||
static WWINLINE float Cross_Product_Y(const Vector3 &a,const Vector3 &b);
|
||||
static WWINLINE float Cross_Product_Z(const Vector3 &a,const Vector3 &b);
|
||||
|
||||
// add and subtract without return by value
|
||||
static WWINLINE void Add(const Vector3 & a,const Vector3 & b,Vector3 * c);
|
||||
static WWINLINE void Subtract(const Vector3 & a,const Vector3 & b,Vector3 * c);
|
||||
|
||||
// Line intersection functions.
|
||||
static WWINLINE float Find_X_At_Y(float y, const Vector3 &p1, const Vector3 &p2);
|
||||
static WWINLINE float Find_X_At_Z(float z, const Vector3 &p1, const Vector3 &p2);
|
||||
static WWINLINE float Find_Y_At_X(float x, const Vector3 &p1, const Vector3 &p2);
|
||||
static WWINLINE float Find_Y_At_Z(float z, const Vector3 &p1, const Vector3 &p2);
|
||||
static WWINLINE float Find_Z_At_X(float x, const Vector3 &p1, const Vector3 &p2);
|
||||
static WWINLINE float Find_Z_At_Y(float z, const Vector3 &p1, const Vector3 &p2);
|
||||
|
||||
// make this vector the min or max of itself and the passed vector
|
||||
WWINLINE void Update_Min(const Vector3 & a);
|
||||
WWINLINE void Update_Max(const Vector3 & a);
|
||||
WWINLINE void Cap_Absolute_To(const Vector3 & a);
|
||||
|
||||
// verify that none of the members of this vector are invalid floats
|
||||
WWINLINE bool Is_Valid(void) const;
|
||||
|
||||
static WWINLINE float Quick_Distance(const Vector3 &p1, const Vector3 &p2);
|
||||
static WWINLINE float Distance(const Vector3 &p1, const Vector3 &p2);
|
||||
|
||||
// Linearly interpolate two Vector3's
|
||||
static void Lerp(const Vector3 & a, const Vector3 & b, float alpha,Vector3 * set_result);
|
||||
|
||||
// Color Conversion
|
||||
WWINLINE unsigned long Convert_To_ABGR( void ) const;
|
||||
WWINLINE unsigned long Convert_To_ARGB( void ) const;
|
||||
};
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Scalar Multiply Operator -- Multiply a vector by a scalar *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector3 operator * (const Vector3 &a,float k)
|
||||
{
|
||||
return Vector3((a.X * k),(a.Y * k),(a.Z * k));
|
||||
}
|
||||
|
||||
WWINLINE Vector3 operator * (float k, const Vector3 &a)
|
||||
{
|
||||
return Vector3((a.X * k),(a.Y * k),(a.Z * k));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Scalar Division Operator -- Divide a vector by a scalar *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector3 operator / (const Vector3 &a,float k)
|
||||
{
|
||||
float ook = 1.0f/k;
|
||||
return Vector3((a.X * ook),(a.Y * ook),(a.Z * ook));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Addition Operator -- Add two vectors *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector3 operator + (const Vector3 &a,const Vector3 &b)
|
||||
{
|
||||
return Vector3(
|
||||
a.X+b.X,
|
||||
a.Y+b.Y,
|
||||
a.Z+b.Z
|
||||
);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Subtraction Operator -- Subract two vectors *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector3 operator - (const Vector3 &a,const Vector3 &b)
|
||||
{
|
||||
return Vector3(
|
||||
a.X-b.X,
|
||||
a.Y-b.Y,
|
||||
a.Z-b.Z
|
||||
);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Inner Product -- Compute the inner or dot product of two vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
//WWINLINE float operator * (const Vector3 &a,const Vector3 &b)
|
||||
//{
|
||||
// return a.X*b.X +
|
||||
// a.Y*b.Y +
|
||||
// a.Z*b.Z;
|
||||
//}
|
||||
|
||||
WWINLINE float Vector3::Dot_Product(const Vector3 &a,const Vector3 &b)
|
||||
{
|
||||
return a.X*b.X +
|
||||
a.Y*b.Y +
|
||||
a.Z*b.Z;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Equality Operator -- Determine if two vectors are identical *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool operator == (const Vector3 &a,const Vector3 &b)
|
||||
{
|
||||
return ( (a.X == b.X) && (a.Y == b.Y) && (a.Z == b.Z));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Inequality Operator -- Determine if two vectors are identical *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool operator != (const Vector3 &a,const Vector3 &b)
|
||||
{
|
||||
return ( (a.X != b.X) || (a.Y != b.Y) || (a.Z != b.Z));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Equal_Within_Epsilon -- Determine if two vectors are identical within e*
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool Equal_Within_Epsilon(const Vector3 &a,const Vector3 &b,float epsilon)
|
||||
{
|
||||
return( (WWMath::Fabs(a.X - b.X) < epsilon) &&
|
||||
(WWMath::Fabs(a.Y - b.Y) < epsilon) &&
|
||||
(WWMath::Fabs(a.Z - b.Z) < epsilon) );
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Cross_Product -- compute the cross product of two vectors *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
WWINLINE Vector3 Vector3::Cross_Product(const Vector3 &a,const Vector3 &b)
|
||||
{
|
||||
return Vector3(
|
||||
(a.Y * b.Z - a.Z * b.Y),
|
||||
(a.Z * b.X - a.X * b.Z),
|
||||
(a.X * b.Y - a.Y * b.X)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
WWINLINE void Vector3::Cross_Product(const Vector3 &a,const Vector3 &b,Vector3 * set_result)
|
||||
{
|
||||
assert(set_result != &a);
|
||||
set_result->X = (a.Y * b.Z - a.Z * b.Y);
|
||||
set_result->Y = (a.Z * b.X - a.X * b.Z);
|
||||
set_result->Z = (a.X * b.Y - a.Y * b.X);
|
||||
}
|
||||
|
||||
WWINLINE void Vector3::Normalized_Cross_Product(const Vector3 &a,const Vector3 &b,Vector3 * set_result)
|
||||
{
|
||||
assert(set_result != &a);
|
||||
set_result->X = (a.Y * b.Z - a.Z * b.Y);
|
||||
set_result->Y = (a.Z * b.X - a.X * b.Z);
|
||||
set_result->Z = (a.X * b.Y - a.Y * b.X);
|
||||
set_result->Normalize();
|
||||
}
|
||||
|
||||
WWINLINE float Vector3::Cross_Product_X(const Vector3 &a,const Vector3 &b)
|
||||
{
|
||||
return a.Y * b.Z - a.Z * b.Y;
|
||||
}
|
||||
|
||||
WWINLINE float Vector3::Cross_Product_Y(const Vector3 &a,const Vector3 &b)
|
||||
{
|
||||
return a.Z * b.X - a.X * b.Z;
|
||||
}
|
||||
|
||||
WWINLINE float Vector3::Cross_Product_Z(const Vector3 &a,const Vector3 &b)
|
||||
{
|
||||
return a.X * b.Y - a.Y * b.X;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector3::Normalize -- Normalizes the vector. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE void Vector3::Normalize()
|
||||
{
|
||||
float len2 = Length2();
|
||||
if (len2 != 0.0f)
|
||||
{
|
||||
float oolen = WWMath::Inv_Sqrt(len2);
|
||||
X *= oolen;
|
||||
Y *= oolen;
|
||||
Z *= oolen;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
WWINLINE Vector3 Normalize(const Vector3 & vec)
|
||||
{
|
||||
float len2 = vec.Length2();
|
||||
if (len2 != 0.0f)
|
||||
{
|
||||
float oolen = WWMath::Inv_Sqrt(len2);
|
||||
return vec * oolen;
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
* Vector3::Length -- Returns the length of the vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE float Vector3::Length() const
|
||||
{
|
||||
return WWMath::Sqrt(Length2());
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector3::Length2 -- Returns the square of the length of the vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE float Vector3::Length2() const
|
||||
{
|
||||
return X*X + Y*Y + Z*Z;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Quick_Length -- returns a quick approximation of the length *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 7/15/98 GTH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE float Vector3::Quick_Length(void) const
|
||||
{
|
||||
// this method of approximating the length comes from Graphics Gems 1 and
|
||||
// supposedly gives an error of +/- 8%
|
||||
float max = WWMath::Fabs(X);
|
||||
float mid = WWMath::Fabs(Y);
|
||||
float min = WWMath::Fabs(Z);
|
||||
float tmp;
|
||||
|
||||
if (max < mid) { tmp = max; max = mid; mid = tmp; }
|
||||
if (max < min) { tmp = max; max = min; min = tmp; }
|
||||
if (mid < min) { tmp = mid; mid = min; min = mid; }
|
||||
|
||||
return max + (11.0f / 32.0f)*mid + (1.0f / 4.0f)*min;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Swap -- swap two Vector3's *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 08/11/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Swap(Vector3 & a,Vector3 & b)
|
||||
{
|
||||
Vector3 tmp(a);
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Lerp -- linearly interpolate two Vector3's without return-by-value *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Lerp(const Vector3 & a, const Vector3 & b, float alpha,Vector3 * set_result)
|
||||
{
|
||||
assert(set_result != NULL);
|
||||
set_result->X = (a.X + (b.X - a.X)*alpha);
|
||||
set_result->Y = (a.Y + (b.Y - a.Y)*alpha);
|
||||
set_result->Z = (a.Z + (b.Z - a.Z)*alpha);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Add -- Add two vector3's without return-by-value *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Add(const Vector3 &a,const Vector3 &b,Vector3 * set_result)
|
||||
{
|
||||
assert(set_result != NULL);
|
||||
set_result->X = a.X + b.X;
|
||||
set_result->Y = a.Y + b.Y;
|
||||
set_result->Z = a.Z + b.Z;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Subtract -- Subtract two vector3's without return-by-value *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Subtract(const Vector3 &a,const Vector3 &b,Vector3 * set_result)
|
||||
{
|
||||
assert(set_result != NULL);
|
||||
set_result->X = a.X - b.X;
|
||||
set_result->Y = a.Y - b.Y;
|
||||
set_result->Z = a.Z - b.Z;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Update_Min -- sets each component of the vector to the min of this and a *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Update_Min(const Vector3 & a)
|
||||
{
|
||||
if (a.X < X) X = a.X;
|
||||
if (a.Y < Y) Y = a.Y;
|
||||
if (a.Z < Z) Z = a.Z;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Update_Max -- Sets each component of the vector to the max of this and a *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Update_Max(const Vector3 & a)
|
||||
{
|
||||
if (a.X > X) X = a.X;
|
||||
if (a.Y > Y) Y = a.Y;
|
||||
if (a.Z > Z) Z = a.Z;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Cap_To_Absolute_Of -- Sets each component of the vector to no larger than the -ve or +ve of*
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/29/99 wst : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Cap_Absolute_To(const Vector3 & a)
|
||||
{
|
||||
if (X > 0)
|
||||
{
|
||||
if (a.X < X) X = a.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (-a.X > X) X = -a.X;
|
||||
}
|
||||
|
||||
if (Y > 0)
|
||||
{
|
||||
if (a.Y < Y) Y = a.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (-a.Y > Y) Y = -a.Y;
|
||||
}
|
||||
|
||||
if (Z > 0)
|
||||
{
|
||||
if (a.Z < Z) Z = a.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (-a.Z > Z) Z = -a.Z;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Scale -- scale this vector by 3 independent scale factors *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Scale(const Vector3 & scale)
|
||||
{
|
||||
X *= scale.X;
|
||||
Y *= scale.Y;
|
||||
Z *= scale.Z;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Rotate_X -- rotates this vector around the X axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Rotate_X(float angle)
|
||||
{
|
||||
Rotate_X(sinf(angle),cosf(angle));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Rotate_X -- Rotates this vector around the x axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Rotate_X(float s_angle,float c_angle)
|
||||
{
|
||||
float tmp_y = Y;
|
||||
float tmp_z = Z;
|
||||
|
||||
Y = c_angle * tmp_y - s_angle * tmp_z;
|
||||
Z = s_angle * tmp_y + c_angle * tmp_z;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Rotate_Y -- Rotates this vector around the y axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Rotate_Y(float angle)
|
||||
{
|
||||
Rotate_Y(sinf(angle),cosf(angle));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Rotate_Y -- Rotates this vector around the Y axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Rotate_Y(float s_angle,float c_angle)
|
||||
{
|
||||
float tmp_x = X;
|
||||
float tmp_z = Z;
|
||||
|
||||
X = c_angle * tmp_x + s_angle * tmp_z;
|
||||
Z = -s_angle * tmp_x + c_angle * tmp_z;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Rotate_Z -- Rotates this vector around the Z axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Rotate_Z(float angle)
|
||||
{
|
||||
Rotate_Z(sinf(angle),cosf(angle));
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Rotate_Z -- Rotates this vector around the Z axis *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Vector3::Rotate_Z(float s_angle,float c_angle)
|
||||
{
|
||||
float tmp_x = X;
|
||||
float tmp_y = Y;
|
||||
|
||||
X = c_angle * tmp_x - s_angle * tmp_y;
|
||||
Y = s_angle * tmp_x + c_angle * tmp_y;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Is_Valid -- Verifies that each component of this vector is a valid float *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE bool Vector3::Is_Valid(void) const
|
||||
{
|
||||
return (WWMath::Is_Valid_Float(X) && WWMath::Is_Valid_Float(Y) && WWMath::Is_Valid_Float(Z));
|
||||
}
|
||||
|
||||
WWINLINE float Vector3::Find_X_At_Y(float y, const Vector3 &p1, const Vector3 &p2)
|
||||
{
|
||||
return(p1.X + ((y - p1.Y) * ((p2.X - p1.X) / (p2.Y - p1.Y))));
|
||||
}
|
||||
WWINLINE float Vector3::Find_X_At_Z(float z, const Vector3 &p1, const Vector3 &p2)
|
||||
{
|
||||
return(p1.X + ((z - p1.Z) * ((p2.X - p1.X) / (p2.Z - p1.Z))));
|
||||
}
|
||||
WWINLINE float Vector3::Find_Y_At_X(float x, const Vector3 &p1, const Vector3 &p2)
|
||||
{
|
||||
return(p1.Y + ((x - p1.X) * ((p2.Y - p1.Y) / (p2.X - p1.X))));
|
||||
}
|
||||
WWINLINE float Vector3::Find_Y_At_Z(float z, const Vector3 &p1, const Vector3 &p2)
|
||||
{
|
||||
return(p1.Y + ((z - p1.Z) * ((p2.Y - p1.Y) / (p2.Z - p1.Z))));
|
||||
}
|
||||
WWINLINE float Vector3::Find_Z_At_X(float x, const Vector3 &p1, const Vector3 &p2)
|
||||
{
|
||||
return(p1.Z + ((x - p1.X) * ((p2.Z - p1.Z) / (p2.X - p1.X))));
|
||||
}
|
||||
WWINLINE float Vector3::Find_Z_At_Y(float y, const Vector3 &p1, const Vector3 &p2)
|
||||
{
|
||||
return(p1.Z + ((y - p1.Y) * ((p2.Z - p1.Z) / (p2.Y - p1.Y))));
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Distance -- Accurate distance calculation. *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/29/1999MLL: Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE float Vector3::Distance(const Vector3 &p1, const Vector3 &p2)
|
||||
{
|
||||
Vector3 temp;
|
||||
temp = p1 - p2;
|
||||
return (temp.Length());
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Quick_Distance -- Fast but inaccurate distance calculation. *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/29/1999MLL: Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE float Vector3::Quick_Distance(const Vector3 &p1, const Vector3 &p2)
|
||||
{
|
||||
Vector3 temp;
|
||||
temp = p1 - p2;
|
||||
return (temp.Quick_Length());
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Convert_To_ABGR -- Converts to SR packed color . *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/29/1999MLL: Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE unsigned long Vector3::Convert_To_ABGR( void ) const
|
||||
{
|
||||
return (unsigned(255)<<24) |
|
||||
(unsigned(Z*255.0f)<<16) |
|
||||
(unsigned(Y*255.0f)<<8) |
|
||||
(unsigned(X*255.0f));
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector3::Convert_To_ARGB -- Converts to packed color . *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 11/29/1999MLL: Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE unsigned long Vector3::Convert_To_ARGB( void ) const
|
||||
{
|
||||
return (unsigned(255)<<24) |
|
||||
(unsigned(X*255.0f)<<16) |
|
||||
(unsigned(Y*255.0f)<<8) |
|
||||
(unsigned(Z*255.0f));
|
||||
}
|
||||
|
||||
#endif /* Vector3_H */
|
||||
|
||||
412
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vector4.h
Normal file
412
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vector4.h
Normal file
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
/* $Header: /Commando/Code/wwmath/vector4.h 16 5/11/01 7:11p Jani_p $ */
|
||||
/***************************************************************************
|
||||
*** Confidential - Westwood Studios ***
|
||||
***************************************************************************
|
||||
* *
|
||||
* Project Name : Westwood 3D *
|
||||
* *
|
||||
* File Name : VECTOR4.H *
|
||||
* *
|
||||
* Programmer : Greg Hjelstrom *
|
||||
* *
|
||||
* Start Date : 02/24/97 *
|
||||
* *
|
||||
* Last Update : June 2, 1997 [GH] *
|
||||
* *
|
||||
*-------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Scalar Division Operator -- Divide a vector by a scalar *
|
||||
* Scalar Multiply Operator -- Multiply a vector by a scalar *
|
||||
* Vector Addition Operator -- Add two vectors *
|
||||
* Vector Subtraction Operator -- Subract two vectors *
|
||||
* Vector Inner Product Operator -- Compute the inner or dot product *
|
||||
* Vector Equality Operator -- Detemine if two vectors are identical *
|
||||
* Vector Inequality Operator -- Detemine if two vectors are identical *
|
||||
* Swap -- swap two Vector4's *
|
||||
* Vector4::Is_Valid -- Vector4::Is_Valid *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef VECTOR4_H
|
||||
#define VECTOR4_H
|
||||
|
||||
#include "always.h"
|
||||
#include "wwmath.h"
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
** Vector4 - 4 dimensional vectors
|
||||
*/
|
||||
class Vector4
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
float X;
|
||||
float Y;
|
||||
float Z;
|
||||
float W;
|
||||
|
||||
|
||||
// Constructors
|
||||
WWINLINE Vector4(void) {};
|
||||
WWINLINE Vector4(const Vector4 & v) { X = v.X; Y = v.Y; Z = v.Z; W = v.W; }
|
||||
WWINLINE Vector4(float x, float y, float z, float w) { X = x; Y = y; Z = z; W = w; }
|
||||
WWINLINE Vector4(const float vector[4]) { X = vector[0]; Y = vector[1]; Z = vector[2]; W = vector[3]; }
|
||||
|
||||
// Assignment
|
||||
WWINLINE Vector4 & operator = (const Vector4 & v) { X = v.X; Y = v.Y; Z = v.Z; W = v.W; return *this; }
|
||||
WWINLINE void Set(float x, float y, float z, float w) { X = x; Y = y; Z = z; W = w; }
|
||||
|
||||
// Array access
|
||||
WWINLINE float & operator [](int i) { return (&X)[i]; }
|
||||
WWINLINE const float & operator [](int i) const { return (&X)[i]; }
|
||||
|
||||
// normalize, compute length
|
||||
void Normalize(void);
|
||||
WWINLINE float Length(void) const;
|
||||
WWINLINE float Length2(void) const;
|
||||
|
||||
// unary operators
|
||||
WWINLINE Vector4 operator-() const { return(Vector4(-X,-Y,-Z,-W)); }
|
||||
WWINLINE Vector4 operator+() const { return *this; }
|
||||
|
||||
WWINLINE Vector4 & operator += (const Vector4 & v) { X += v.X; Y += v.Y; Z += v.Z; W += v.W; return *this; }
|
||||
WWINLINE Vector4 & operator -= (const Vector4 & v) { X -= v.X; Y -= v.Y; Z -= v.Z; W += v.W; return *this; }
|
||||
WWINLINE Vector4 & operator *= (float k) { X = X*k; Y=Y*k; Z=Z*k; W=W*k; return *this; }
|
||||
WWINLINE Vector4 & operator /= (float k) { k=1.0f/k; X = X*k; Y=Y*k; Z=Z*k; W=W*k; return *this; }
|
||||
|
||||
// scalar multiplication, division
|
||||
WWINLINE friend Vector4 operator * (const Vector4 &a,float k);
|
||||
WWINLINE friend Vector4 operator * (float k,const Vector4 &a);
|
||||
WWINLINE friend Vector4 operator / (const Vector4 &a,float k);
|
||||
|
||||
// vector addition,subtraction
|
||||
WWINLINE friend Vector4 operator + (const Vector4 &a,const Vector4 &b);
|
||||
WWINLINE friend Vector4 operator - (const Vector4 &a,const Vector4 &b);
|
||||
|
||||
// dot product / inner product
|
||||
WWINLINE friend float operator * (const Vector4 &a,const Vector4 &b);
|
||||
static WWINLINE float Dot_Product(const Vector4 &a,const Vector4 &b);
|
||||
|
||||
// Equality operators
|
||||
friend bool operator == (const Vector4 &a,const Vector4 &b);
|
||||
friend bool operator != (const Vector4 &a,const Vector4 &b);
|
||||
|
||||
// Linearly interpolate between two Vector4's
|
||||
static Vector4 Lerp(const Vector4 & a, const Vector4 & b, float alpha);
|
||||
static void Lerp(const Vector4 & a, const Vector4 & b, float alpha,Vector4 * set_result);
|
||||
|
||||
// verify that none of the members of this vector are invalid floats
|
||||
WWINLINE bool Is_Valid(void) const;
|
||||
};
|
||||
|
||||
/**************************************************************************
|
||||
* Scalar Multiply Operator -- Multiply a vector by a scalar *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector4 operator * (const Vector4 &a,float k)
|
||||
{
|
||||
return Vector4((a.X * k),(a.Y * k),(a.Z * k),(a.W * k));
|
||||
}
|
||||
|
||||
WWINLINE Vector4 operator * (float k, const Vector4 &a)
|
||||
{
|
||||
return a*k;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Scalar Division Operator -- Divide a vector by a scalar *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector4 operator / (const Vector4 &a,float k)
|
||||
{
|
||||
float ook=1.0f/k;
|
||||
return Vector4((a[0] * ook),(a[1] * ook),(a[2] * ook),(a[3] * ook));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Addition Operator -- Add two vectors *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector4 operator + (const Vector4 &a,const Vector4 &b)
|
||||
{
|
||||
return Vector4(
|
||||
a[0]+b[0],
|
||||
a[1]+b[1],
|
||||
a[2]+b[2],
|
||||
a[3]+b[3]
|
||||
);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Subtraction Operator -- Subract two vectors *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 02/24/1997 GH : Created. *
|
||||
*========================================================================*/
|
||||
WWINLINE Vector4 operator - (const Vector4 &a,const Vector4 &b)
|
||||
{
|
||||
return Vector4(
|
||||
a[0]-b[0],
|
||||
a[1]-b[1],
|
||||
a[2]-b[2],
|
||||
a[3]-b[3]
|
||||
);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Inner Product -- Compute the inner or dot product of two vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE float operator * (const Vector4 &a,const Vector4 &b)
|
||||
{
|
||||
return a[0]*b[0] +
|
||||
a[1]*b[1] +
|
||||
a[2]*b[2] +
|
||||
a[3]*b[3];
|
||||
}
|
||||
|
||||
WWINLINE float Vector4::Dot_Product(const Vector4 &a,const Vector4 &b)
|
||||
{
|
||||
return a*b;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Equality Operator -- Detemine if two vectors are identical *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool operator == (const Vector4 &a,const Vector4 &b)
|
||||
{
|
||||
return ( (a[0] == b[0]) && (a[1] == b[1]) && (a[2] == b[2]) && (a[3] == b[3]));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector Inequality Operator -- Detemine if two vectors are identical *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE bool operator != (const Vector4 &a,const Vector4 &b)
|
||||
{
|
||||
return ( (a[0] != b[0]) || (a[1] != b[1]) || (a[2] != b[2]) || (a[3] != b[3]));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector4::Normalize -- Normalizes the vector. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE void Vector4::Normalize()
|
||||
{
|
||||
float len2 = Length2();
|
||||
if (len2 != 0.0f) {
|
||||
float oolen = WWMath::Inv_Sqrt(len2);
|
||||
X *= oolen;
|
||||
Y *= oolen;
|
||||
Z *= oolen;
|
||||
W *= oolen;
|
||||
}
|
||||
}
|
||||
|
||||
WWINLINE Vector4 Normalize(const Vector4 & vec)
|
||||
{
|
||||
float len2 = vec.Length2();
|
||||
if (len2 != 0.0f) {
|
||||
float oolen = WWMath::Inv_Sqrt(len2);
|
||||
return vec * oolen;
|
||||
}
|
||||
return Vector4(0.0f,0.0f,0.0f,0.0f);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector4::Length -- Returns the length of the vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE float Vector4::Length() const
|
||||
{
|
||||
return WWMath::Sqrt(Length2());
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Vector4::Length -- Returns the square of the length of the vector *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
*========================================================================*/
|
||||
WWINLINE float Vector4::Length2() const
|
||||
{
|
||||
return X*X + Y*Y + Z*Z + W*W;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************************************
|
||||
* Swap -- swap two Vector4's *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 06/02/1997 GH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE void Swap(Vector4 & a,Vector4 & b)
|
||||
{
|
||||
Vector4 tmp(a);
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Lerp -- linearly interpolate two Vector4's by an interpolation factor. *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: No checking is done to ensure that alpha is between 0 and 1. *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 01/14/1999 NH : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE Vector4 Lerp(const Vector4 & a, const Vector4 & b, float alpha)
|
||||
{
|
||||
return Vector4(
|
||||
(a.X + (b.X - a.X)*alpha),
|
||||
(a.Y + (b.Y - a.Y)*alpha),
|
||||
(a.Z + (b.Z - a.Z)*alpha),
|
||||
(a.W + (b.W - a.W)*alpha)
|
||||
);
|
||||
}
|
||||
|
||||
WWINLINE Vector4 Vector4::Lerp(const Vector4 & a, const Vector4 & b, float alpha)
|
||||
{
|
||||
return Vector4(
|
||||
(a.X + (b.X - a.X)*alpha),
|
||||
(a.Y + (b.Y - a.Y)*alpha),
|
||||
(a.Z + (b.Z - a.Z)*alpha),
|
||||
(a.W + (b.W - a.W)*alpha)
|
||||
);
|
||||
}
|
||||
|
||||
WWINLINE void Vector4::Lerp(const Vector4 & a, const Vector4 & b, float alpha,Vector4 * set_result)
|
||||
{
|
||||
set_result->X = (a.X + (b.X - a.X)*alpha);
|
||||
set_result->Y = (a.Y + (b.Y - a.Y)*alpha);
|
||||
set_result->Z = (a.Z + (b.Z - a.Z)*alpha);
|
||||
set_result->X = (a.W + (b.W - a.W)*alpha);
|
||||
}
|
||||
|
||||
/***********************************************************************************************
|
||||
* Vector4::Is_Valid -- Vector4::Is_Valid *
|
||||
* *
|
||||
* verifies that all members of this vector are valid floats *
|
||||
* *
|
||||
* *
|
||||
* INPUT: *
|
||||
* *
|
||||
* OUTPUT: *
|
||||
* *
|
||||
* WARNINGS: *
|
||||
* *
|
||||
* HISTORY: *
|
||||
* 10/18/99 gth : Created. *
|
||||
*=============================================================================================*/
|
||||
WWINLINE bool Vector4::Is_Valid(void) const
|
||||
{
|
||||
return (WWMath::Is_Valid_Float(X) && WWMath::Is_Valid_Float(Y) && WWMath::Is_Valid_Float(Z) && WWMath::Is_Valid_Float(W));
|
||||
}
|
||||
|
||||
|
||||
#endif /* VECTOR4_H */
|
||||
|
||||
686
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vehiclecurve.cpp
Normal file
686
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vehiclecurve.cpp
Normal file
@@ -0,0 +1,686 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 : LevelEdit *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/wwmath/vehiclecurve.cpp $*
|
||||
* *
|
||||
* Author:: Patrick Smith *
|
||||
* *
|
||||
* $Modtime:: 6/12/01 10:02a $*
|
||||
* *
|
||||
* $Revision:: 8 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "vehiclecurve.h"
|
||||
#include "vector3.h"
|
||||
#include "matrix3d.h"
|
||||
#include "persistfactory.h"
|
||||
#include "wwmathids.h"
|
||||
#include "wwmemlog.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Save-Load stuff
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
SimplePersistFactoryClass<VehicleCurveClass,WWMATH_CHUNKID_VEHICLECURVE> _VehicleCurveFactory;
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Save/Load constants
|
||||
////////////////////////////////////////////////////////////////
|
||||
enum
|
||||
{
|
||||
CHUNKID_PARENT = 0x11071217,
|
||||
CHUNKID_ARC_INFO,
|
||||
CHUNKID_VARIABLES
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VARID_IS_DIRTY = 1,
|
||||
VARID_RADIUS,
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Local prototypes
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
bool Find_Tangent (const Vector3 ¢er, float radius, const Vector3 &point, bool clockwise, float *result);
|
||||
float Get_Angle_Delta (float angle1, float angle2, bool clockwise);
|
||||
void Find_Turn_Arc (const Matrix3D &transform, float radius, const Vector3 &prev_pt, const Vector3 &curr_pt, const Vector3 &next_pt, Vector3 *arc_center, bool *is_right_turn);
|
||||
void Find_Tangents (float radius, const Vector3 &prev_pt, const Vector3 &curr_pt, const Vector3 &next_pt, const Vector3 &arc_center, bool is_right_turn, float *point_angle, float *angle_in_delta, float *angle_out_delta);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Find_Tangent
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
Find_Tangent
|
||||
(
|
||||
const Vector3 & center,
|
||||
float radius,
|
||||
const Vector3 & point,
|
||||
bool clockwise,
|
||||
float * result
|
||||
)
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
//
|
||||
// Calculate the distance from the point to the center of the circle
|
||||
//
|
||||
float delta_x = point.X - center.X;
|
||||
float delta_y = point.Y - center.Y;
|
||||
float dist = ::sqrt (delta_x * delta_x + delta_y * delta_y);
|
||||
if (dist >= radius) {
|
||||
|
||||
//
|
||||
// Determine the offset angle (from the line between the point and center)
|
||||
// where the 2 tangent points lie.
|
||||
//
|
||||
float angle_offset = WWMath::Acos (radius / dist);
|
||||
float base_angle = WWMath::Atan2 (delta_x, -delta_y);
|
||||
base_angle = WWMath::Wrap (base_angle, 0, DEG_TO_RADF (360));
|
||||
|
||||
//
|
||||
// Determine which tangent angle we would come across first, depending
|
||||
// on our orientation
|
||||
//
|
||||
float angle = 0;
|
||||
if (clockwise) {
|
||||
angle = base_angle - angle_offset;
|
||||
} else {
|
||||
angle = base_angle + angle_offset;
|
||||
}
|
||||
angle = WWMath::Wrap (angle, 0, DEG_TO_RADF (360));
|
||||
(*result) = angle;
|
||||
|
||||
retval = true;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Get_Angle_Delta
|
||||
//
|
||||
// Angle deltas need to be wrapped around 360 degrees differently
|
||||
// depending on the orientation (clockwise/counterclockwise). This
|
||||
// function takes orientation into consideration when determining
|
||||
// the delta.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
float
|
||||
Get_Angle_Delta
|
||||
(
|
||||
float angle1,
|
||||
float angle2,
|
||||
bool clockwise
|
||||
)
|
||||
{
|
||||
float result = angle1 - angle2;
|
||||
|
||||
if (clockwise) {
|
||||
if (angle1 < angle2) {
|
||||
result = angle1 - (angle2 - DEG_TO_RADF (360));
|
||||
}
|
||||
} else {
|
||||
if (angle1 > angle2) {
|
||||
result = (angle1 - DEG_TO_RADF (360)) - angle2;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Find_Turn_Arc
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
Find_Turn_Arc
|
||||
(
|
||||
const Matrix3D & transform,
|
||||
float radius,
|
||||
const Vector3 & prev_pt,
|
||||
const Vector3 & curr_pt,
|
||||
const Vector3 & next_pt,
|
||||
Vector3 * arc_center,
|
||||
bool * is_right_turn
|
||||
)
|
||||
{
|
||||
//
|
||||
// The center of the turn arc can lie anywhere on the circle centered
|
||||
// at the current point and 'radius' meters in radius.
|
||||
//
|
||||
// We will assume the optimal center of the turn arc will lie at
|
||||
// the point halfway between the angles formed by the (prev-curr) and
|
||||
// (next-curr) vectors.
|
||||
//
|
||||
float angle1 = ::WWMath::Atan2 ((prev_pt.Y - curr_pt.Y), prev_pt.X - curr_pt.X);
|
||||
angle1 = WWMath::Wrap (angle1, 0, DEG_TO_RADF (360));
|
||||
|
||||
float angle2 = ::WWMath::Atan2 ((next_pt.Y - curr_pt.Y), next_pt.X - curr_pt.X);
|
||||
angle2 = WWMath::Wrap (angle2, 0, DEG_TO_RADF (360));
|
||||
|
||||
float avg_angle = (angle1 + angle2) * 0.5F;
|
||||
|
||||
//
|
||||
// Find the shortest delta between the two angles (either clockwise or
|
||||
// counterclockwise).
|
||||
//
|
||||
float delta1 = WWMath::Fabs (::Get_Angle_Delta (angle1, angle2, true));
|
||||
float delta2 = WWMath::Fabs (::Get_Angle_Delta (angle1, angle2, false));
|
||||
if (delta1 < delta2) {
|
||||
avg_angle = angle1 - (delta1 * 0.5F);
|
||||
} else {
|
||||
avg_angle = angle1 + (delta2 * 0.5F);
|
||||
}
|
||||
|
||||
//
|
||||
// Find the point on the circle at this angle
|
||||
//
|
||||
arc_center->X = curr_pt.X + (radius * ::WWMath::Cos (avg_angle));
|
||||
arc_center->Y = curr_pt.Y + (radius * ::WWMath::Sin (avg_angle));
|
||||
arc_center->Z = curr_pt.Z;
|
||||
|
||||
//
|
||||
// Will we be making a right turn or a left turn?
|
||||
//
|
||||
Vector3 rel_center;
|
||||
Matrix3D::Inverse_Transform_Vector (transform, *arc_center, &rel_center);
|
||||
(*is_right_turn) = (rel_center.Y > 0);
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Find_Tangents
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
Find_Tangents
|
||||
(
|
||||
float radius,
|
||||
const Vector3 & prev_pt,
|
||||
const Vector3 & curr_pt,
|
||||
const Vector3 & next_pt,
|
||||
const Vector3 & arc_center,
|
||||
bool is_right_turn,
|
||||
float * point_angle,
|
||||
float * angle_in_delta,
|
||||
float * angle_out_delta
|
||||
)
|
||||
{
|
||||
|
||||
//
|
||||
// Find the 'in' and 'out' tangent angles
|
||||
//
|
||||
float angle_in = 0;
|
||||
float angle_out = 0;
|
||||
bool valid_in = ::Find_Tangent (arc_center, radius, prev_pt, is_right_turn, &angle_in);
|
||||
bool valid_out = ::Find_Tangent (arc_center, radius, next_pt, !is_right_turn, &angle_out);
|
||||
|
||||
//
|
||||
// Find the angle where the current position lies on the turn arc
|
||||
//
|
||||
(*point_angle) = ::WWMath::Atan2 (curr_pt.X - arc_center.X, -(curr_pt.Y - arc_center.Y));
|
||||
(*point_angle) = WWMath::Wrap ((*point_angle), 0, DEG_TO_RADF (360));
|
||||
|
||||
//
|
||||
// If the tangent-in is valid, find its delta from the 'point angle.
|
||||
//
|
||||
if (valid_in) {
|
||||
(*angle_in_delta) = ::Get_Angle_Delta (angle_in, (*point_angle), is_right_turn);
|
||||
} else {
|
||||
(*angle_in_delta) = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// If the tangent-out is valid, find its delta from the 'point angle.
|
||||
//
|
||||
if (valid_out) {
|
||||
(*angle_out_delta) = ::Get_Angle_Delta (angle_out, (*point_angle), !is_right_turn);
|
||||
} else {
|
||||
(*angle_out_delta) = 0;
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Update_Arc_List
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
VehicleCurveClass::Update_Arc_List (void)
|
||||
{
|
||||
WWMEMLOG(MEM_PATHFIND);
|
||||
m_ArcList.Delete_All ();
|
||||
|
||||
//
|
||||
// Bail out if there is nothing to do
|
||||
//
|
||||
int count = Key_Count ();
|
||||
if (count == 0) {
|
||||
return ;
|
||||
}
|
||||
|
||||
//
|
||||
// Add a record for the starting point of the arc...
|
||||
//
|
||||
ArcInfoStruct arc_start;
|
||||
arc_start.point_in = Keys[0].Point;
|
||||
arc_start.point_out = Keys[0].Point;
|
||||
arc_start.center = Keys[0].Point;
|
||||
arc_start.point_angle = 0;
|
||||
arc_start.radius = 0;
|
||||
arc_start.angle_in_delta = 0;
|
||||
arc_start.angle_out_delta = 0;
|
||||
m_ArcList.Add (arc_start);
|
||||
|
||||
//
|
||||
// Loop over each 'interior' point and generate arc information
|
||||
// for each.
|
||||
//
|
||||
for (int index = 1; index < count - 1; index ++) {
|
||||
|
||||
//
|
||||
// Get information about the previous, next, and current points.
|
||||
//
|
||||
Vector3 prev_pt;
|
||||
Vector3 next_pt;
|
||||
Vector3 curr_pt;
|
||||
float time = 0;
|
||||
Get_Key (index-1, &prev_pt, &time);
|
||||
Get_Key (index, &curr_pt, &time);
|
||||
Get_Key (index+1, &next_pt, &time);
|
||||
|
||||
//
|
||||
// Determine the last known point on the path
|
||||
//
|
||||
Vector3 last_path_pt = m_ArcList[index-1].point_out;
|
||||
|
||||
//
|
||||
// Create a transformation matrix to simulate the vehicle's position and
|
||||
// orientation at the last point...
|
||||
//
|
||||
Vector3 x_vector (curr_pt - last_path_pt);
|
||||
Vector3 z_vector (0, 0, 1);
|
||||
x_vector.Normalize ();
|
||||
#ifdef ALLOW_TEMPORARIES
|
||||
Vector3 y_vector = Vector3::Cross_Product (x_vector, z_vector);
|
||||
#else
|
||||
Vector3 y_vector;
|
||||
Vector3::Cross_Product (x_vector, z_vector, &y_vector);
|
||||
#endif
|
||||
Matrix3D tm (x_vector, y_vector, z_vector, last_path_pt);
|
||||
|
||||
//
|
||||
// Find where the turn arc should be centered and whether we should
|
||||
// make a right-turn or a left turn...
|
||||
//
|
||||
bool is_right_turn = false;
|
||||
Vector3 arc_center (0, 0, 0);
|
||||
::Find_Turn_Arc ( tm,
|
||||
m_Radius,
|
||||
last_path_pt,
|
||||
curr_pt,
|
||||
next_pt,
|
||||
&arc_center,
|
||||
&is_right_turn);
|
||||
|
||||
//
|
||||
// Determine where the vehicle should enter and exit the turn
|
||||
//
|
||||
float angle_in_delta = 0;
|
||||
float angle_out_delta = 0;
|
||||
float point_angle = 0;
|
||||
::Find_Tangents ( m_Radius,
|
||||
last_path_pt,
|
||||
curr_pt,
|
||||
next_pt,
|
||||
arc_center,
|
||||
is_right_turn,
|
||||
&point_angle,
|
||||
&angle_in_delta,
|
||||
&angle_out_delta);
|
||||
|
||||
//
|
||||
// Determine at what points these angles intersect the arc
|
||||
//
|
||||
Vector3 point_in (0, 0, 0);
|
||||
point_in.X = arc_center.X + (m_Radius * ::WWMath::Sin (point_angle + angle_in_delta));
|
||||
point_in.Y = arc_center.Y + (m_Radius * -::WWMath::Cos (point_angle + angle_in_delta));
|
||||
|
||||
Vector3 point_out (0, 0, 0);
|
||||
point_out.X = arc_center.X + (m_Radius * ::WWMath::Sin (point_angle + angle_out_delta));
|
||||
point_out.Y = arc_center.Y + (m_Radius * -::WWMath::Cos (point_angle + angle_out_delta));
|
||||
|
||||
//
|
||||
// Sanity check to ensure the vehicle doesn't try to go the long way around the
|
||||
// turn arc...
|
||||
//
|
||||
if ( angle_in_delta > DEG_TO_RADF (200) || angle_out_delta > DEG_TO_RADF (200) ||
|
||||
angle_in_delta < -DEG_TO_RADF (200) || angle_out_delta < -DEG_TO_RADF (200) )
|
||||
{
|
||||
//
|
||||
// Record information about this arc
|
||||
//
|
||||
ArcInfoStruct arc_info;
|
||||
arc_info.center = curr_pt;
|
||||
arc_info.point_angle = 0;
|
||||
arc_info.point_in = curr_pt;
|
||||
arc_info.point_out = curr_pt;
|
||||
arc_info.radius = 0;
|
||||
arc_info.angle_in_delta = 0;
|
||||
arc_info.angle_out_delta = 0;
|
||||
m_ArcList.Add (arc_info);
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// Record information about this arc
|
||||
//
|
||||
ArcInfoStruct arc_info;
|
||||
arc_info.center = arc_center;
|
||||
arc_info.point_angle = point_angle;
|
||||
arc_info.point_in = point_in;
|
||||
arc_info.point_out = point_out;
|
||||
arc_info.radius = m_Radius;
|
||||
arc_info.angle_in_delta = angle_in_delta;
|
||||
arc_info.angle_out_delta = angle_out_delta;
|
||||
m_ArcList.Add (arc_info);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Add a record for the starting point of the arc...
|
||||
//
|
||||
if (count > 1) {
|
||||
ArcInfoStruct arc_end;
|
||||
arc_end.point_in = Keys[count-1].Point;
|
||||
arc_end.point_out = Keys[count-1].Point;
|
||||
arc_end.center = Keys[count-1].Point;
|
||||
arc_end.point_angle = 0;
|
||||
arc_end.radius = 0;
|
||||
arc_end.angle_in_delta = 0;
|
||||
arc_end.angle_out_delta = 0;
|
||||
m_ArcList.Add (arc_end);
|
||||
}
|
||||
|
||||
m_IsDirty = false;
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Evaluate
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
VehicleCurveClass::Evaluate (float time, Vector3 *set_val)
|
||||
{
|
||||
int count = Keys.Count ();
|
||||
m_Sharpness = 0;
|
||||
|
||||
if (time < Keys[0].Time) {
|
||||
*set_val = Keys[0].Point;
|
||||
m_LastTime = Keys[0].Time;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time >= Keys[count - 1].Time) {
|
||||
*set_val = Keys[count - 1].Point;
|
||||
m_LastTime = Keys[count - 1].Time;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the arc information if any of the keys have changed...
|
||||
//
|
||||
if (m_IsDirty) {
|
||||
Update_Arc_List ();
|
||||
}
|
||||
|
||||
//
|
||||
// Determine which segment we are on
|
||||
//
|
||||
int index0 = 0;
|
||||
int index1 = 0;
|
||||
float seg_time = 0;
|
||||
Find_Interval (time, &index0, &index1, &seg_time);
|
||||
|
||||
ArcInfoStruct &arc_info0 = m_ArcList[index0];
|
||||
ArcInfoStruct &arc_info1 = m_ArcList[index1];
|
||||
|
||||
//
|
||||
// Determine the lengths of each segment of this curve.
|
||||
// The segments are:
|
||||
// - Exit curve from prev point
|
||||
// - Straight line from exit of last curve to enter of this curve
|
||||
// - Enter curve for the current point
|
||||
//
|
||||
float arc_length0 = arc_info0.radius * WWMath::Fabs (arc_info0.angle_out_delta);
|
||||
float arc_length1 = arc_info1.radius * WWMath::Fabs (arc_info1.angle_in_delta);
|
||||
float other_length = ((arc_info1.point_in - arc_info0.point_out).Length ()) / 2;
|
||||
float total_length = arc_length0 + arc_length1 + other_length;
|
||||
|
||||
//
|
||||
// Determine at what times we should switch between parts of the segment
|
||||
//
|
||||
float time1 = arc_length0 / total_length;
|
||||
float time2 = (arc_length0 + other_length) / total_length;
|
||||
|
||||
//
|
||||
// Determine which part of the segment we are on
|
||||
//
|
||||
if (seg_time < time1) {
|
||||
|
||||
//
|
||||
// We are on the initial curve of the segment, so calculate where
|
||||
// on the curve we are...
|
||||
//
|
||||
//float percent = seg_time / time1;
|
||||
//float angle = arc_info0.point_angle + (arc_info0.angle_out_delta) * percent;
|
||||
float angle = arc_info0.point_angle + arc_info0.angle_out_delta;
|
||||
|
||||
set_val->X = arc_info0.center.X + (arc_info0.radius * ::WWMath::Sin (angle));
|
||||
set_val->Y = arc_info0.center.Y + (arc_info0.radius * -::WWMath::Cos (angle));
|
||||
|
||||
m_Sharpness = WWMath::Clamp (WWMath::Fabs (arc_info0.angle_out_delta) / DEG_TO_RADF (15), 0, 1.0F);
|
||||
m_SharpnessPos.X = set_val->X;
|
||||
m_SharpnessPos.Y = set_val->Y;
|
||||
m_SharpnessPos.Z = Keys[index0].Point.Z + (Keys[index1].Point.Z - Keys[index0].Point.Z) * seg_time;
|
||||
|
||||
m_LastTime = Keys[index0].Time + (Keys[index1].Time - Keys[index0].Time) * time1;
|
||||
|
||||
} else if (seg_time < time2) {
|
||||
|
||||
//
|
||||
// We are on the line between the two curves, so calculate where on
|
||||
// the line we are
|
||||
//
|
||||
float percent = (seg_time - time1) / (time2 - time1);
|
||||
|
||||
if (percent == 0) {
|
||||
set_val->X = arc_info0.point_out.X;
|
||||
set_val->Y = arc_info0.point_out.Y;
|
||||
} else {
|
||||
set_val->X = arc_info1.point_in.X;
|
||||
set_val->Y = arc_info1.point_in.Y;
|
||||
}
|
||||
|
||||
//set_val->X = arc_info0.point_out.X + (arc_info1.point_in.X - arc_info0.point_out.X) * percent;
|
||||
//set_val->Y = arc_info0.point_out.Y + (arc_info1.point_in.Y - arc_info0.point_out.Y) * percent;
|
||||
|
||||
m_Sharpness = WWMath::Clamp (WWMath::Fabs (arc_info1.angle_out_delta) / DEG_TO_RADF (15), 0, 1.0F);
|
||||
m_SharpnessPos = arc_info1.point_in;
|
||||
|
||||
m_LastTime = Keys[index0].Time + (Keys[index1].Time - Keys[index0].Time) * time2;
|
||||
|
||||
} else {
|
||||
|
||||
//
|
||||
// We are on the ending curve of the segment, so calculate where
|
||||
// on the curve we are...
|
||||
//
|
||||
/*float percent = 1.0F - ((seg_time - time2) / (1.0F - time2));
|
||||
float angle = arc_info1.point_angle + (arc_info1.angle_in_delta * percent);
|
||||
|
||||
set_val->X = arc_info1.center.X + (arc_info1.radius * ::WWMath::Sin (angle));
|
||||
set_val->Y = arc_info1.center.Y + (arc_info1.radius * -::WWMath::Cos (angle)); */
|
||||
|
||||
float angle = arc_info1.point_angle + (arc_info1.angle_out_delta);
|
||||
|
||||
set_val->X = arc_info1.center.X + (arc_info1.radius * ::WWMath::Sin (angle));
|
||||
set_val->Y = arc_info1.center.Y + (arc_info1.radius * -::WWMath::Cos (angle));
|
||||
|
||||
m_Sharpness = WWMath::Clamp (WWMath::Fabs (arc_info1.angle_out_delta) / DEG_TO_RADF (15), 0, 1.0F);
|
||||
m_SharpnessPos.X = set_val->X;
|
||||
m_SharpnessPos.Y = set_val->Y;
|
||||
m_SharpnessPos.Z = Keys[index0].Point.Z + (Keys[index1].Point.Z - Keys[index0].Point.Z) * seg_time;
|
||||
|
||||
m_LastTime = Keys[index1].Time;
|
||||
}
|
||||
|
||||
//
|
||||
// Our Z value is just a linear interpolation
|
||||
//
|
||||
set_val->Z = Keys[index0].Point.Z + (Keys[index1].Point.Z - Keys[index0].Point.Z) * seg_time;
|
||||
return ;
|
||||
}
|
||||
|
||||
const PersistFactoryClass & VehicleCurveClass::Get_Factory(void) const
|
||||
{
|
||||
return _VehicleCurveFactory;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Save
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
VehicleCurveClass::Save (ChunkSaveClass &csave)
|
||||
{
|
||||
csave.Begin_Chunk (CHUNKID_PARENT);
|
||||
Curve3DClass::Save (csave);
|
||||
csave.End_Chunk ();
|
||||
|
||||
csave.Begin_Chunk (CHUNKID_VARIABLES);
|
||||
|
||||
//
|
||||
// Save each variable to its own microchunk
|
||||
//
|
||||
WRITE_MICRO_CHUNK (csave, VARID_IS_DIRTY, m_IsDirty);
|
||||
WRITE_MICRO_CHUNK (csave, VARID_RADIUS, m_Radius);
|
||||
|
||||
csave.End_Chunk ();
|
||||
|
||||
//
|
||||
// Save each arc info struct to its own chunk
|
||||
//
|
||||
for (int index = 0; index < m_ArcList.Count (); index ++) {
|
||||
ArcInfoStruct &arc_info = m_ArcList[index];
|
||||
|
||||
csave.Begin_Chunk (CHUNKID_ARC_INFO);
|
||||
csave.Write (&arc_info, sizeof (arc_info));
|
||||
csave.End_Chunk ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Load
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool
|
||||
VehicleCurveClass::Load (ChunkLoadClass &cload)
|
||||
{
|
||||
while (cload.Open_Chunk ()) {
|
||||
switch (cload.Cur_Chunk_ID ()) {
|
||||
|
||||
case CHUNKID_PARENT:
|
||||
Curve3DClass::Load (cload);
|
||||
break;
|
||||
|
||||
case CHUNKID_ARC_INFO:
|
||||
{
|
||||
ArcInfoStruct arc_info;
|
||||
cload.Read (&arc_info, sizeof (arc_info));
|
||||
m_ArcList.Add (arc_info);
|
||||
}
|
||||
break;
|
||||
|
||||
case CHUNKID_VARIABLES:
|
||||
Load_Variables (cload);
|
||||
break;
|
||||
}
|
||||
|
||||
cload.Close_Chunk ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Load_Variables
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void
|
||||
VehicleCurveClass::Load_Variables (ChunkLoadClass &cload)
|
||||
{
|
||||
//
|
||||
// Loop through all the microchunks that define the variables
|
||||
//
|
||||
while (cload.Open_Micro_Chunk ()) {
|
||||
switch (cload.Cur_Micro_Chunk_ID ()) {
|
||||
|
||||
READ_MICRO_CHUNK (cload, VARID_IS_DIRTY, m_IsDirty);
|
||||
READ_MICRO_CHUNK (cload, VARID_RADIUS, m_Radius);
|
||||
}
|
||||
|
||||
cload.Close_Micro_Chunk ();
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
210
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vehiclecurve.h
Normal file
210
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vehiclecurve.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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 : LevelEdit *
|
||||
* *
|
||||
* $Archive:: /VSS_Sync/wwmath/vehiclecurve.h $*
|
||||
* *
|
||||
* Author:: Patrick Smith *
|
||||
* *
|
||||
* $Modtime:: 6/13/01 2:18p $*
|
||||
* *
|
||||
* $Revision:: 6 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef __VEHICLE_CURVE_H
|
||||
#define __VEHICLE_CURVE_H
|
||||
|
||||
#include "curve.h"
|
||||
#include "vector.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// VehicleCurveClass
|
||||
//
|
||||
// A vehicle curve represents the path a vehicle would take through a series of points.
|
||||
// Each point on the curve passes through a turn-arc of the vehicle. The size of this
|
||||
// arc is determined by the turn radius which is used to initialize the curve.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class VehicleCurveClass : public Curve3DClass
|
||||
{
|
||||
public:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Public constructors/destructors
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
VehicleCurveClass (void)
|
||||
: m_IsDirty (true),
|
||||
m_Radius (0),
|
||||
m_LastTime (0),
|
||||
m_Sharpness (0),
|
||||
m_SharpnessPos (0, 0, 0),
|
||||
Curve3DClass () { }
|
||||
|
||||
VehicleCurveClass (float radius)
|
||||
: m_IsDirty (true),
|
||||
m_Radius (radius),
|
||||
m_LastTime (0),
|
||||
m_Sharpness (0),
|
||||
m_SharpnessPos (0, 0, 0),
|
||||
Curve3DClass () { }
|
||||
|
||||
virtual ~VehicleCurveClass () {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Public methods
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
void Initialize_Arc (float radius);
|
||||
|
||||
//
|
||||
// From Curve3DClass
|
||||
//
|
||||
void Evaluate (float time, Vector3 *set_val);
|
||||
void Set_Key (int i,const Vector3 & point);
|
||||
int Add_Key (const Vector3 & point,float t);
|
||||
void Remove_Key (int i);
|
||||
void Clear_Keys (void);
|
||||
|
||||
//
|
||||
// Vehicle curve specific
|
||||
//
|
||||
float Get_Current_Sharpness (Vector3 *position) const { *position = m_SharpnessPos; return m_Sharpness; }
|
||||
float Get_Last_Eval_Time (void) const { return m_LastTime; }
|
||||
|
||||
//
|
||||
// Save-load support
|
||||
//
|
||||
virtual const PersistFactoryClass & Get_Factory(void) const;
|
||||
virtual bool Save(ChunkSaveClass &csave);
|
||||
virtual bool Load(ChunkLoadClass &cload);
|
||||
|
||||
protected:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Protected methods
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
void Update_Arc_List (void);
|
||||
void Load_Variables (ChunkLoadClass &cload);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Protected data types
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
typedef struct _ArcInfoStruct
|
||||
{
|
||||
Vector3 center;
|
||||
Vector3 point_in;
|
||||
Vector3 point_out;
|
||||
float point_angle;
|
||||
float radius;
|
||||
float angle_in_delta;
|
||||
float angle_out_delta;
|
||||
|
||||
_ArcInfoStruct (void)
|
||||
: center (0, 0, 0),
|
||||
point_in (0, 0, 0),
|
||||
point_out (0, 0, 0),
|
||||
point_angle (0),
|
||||
radius (0),
|
||||
angle_in_delta (0),
|
||||
angle_out_delta (0) { }
|
||||
|
||||
bool operator== (const _ArcInfoStruct &src) { return false; }
|
||||
bool operator!= (const _ArcInfoStruct &src) { return true; }
|
||||
|
||||
} ArcInfoStruct;
|
||||
|
||||
typedef DynamicVectorClass<ArcInfoStruct> ARC_LIST;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Protected member data
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
bool m_IsDirty;
|
||||
float m_Radius;
|
||||
ARC_LIST m_ArcList;
|
||||
|
||||
float m_LastTime;
|
||||
float m_Sharpness;
|
||||
Vector3 m_SharpnessPos;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Set_Key
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
inline void
|
||||
VehicleCurveClass::Set_Key (int i,const Vector3 & point)
|
||||
{
|
||||
m_IsDirty = true;
|
||||
Curve3DClass::Set_Key (i, point);
|
||||
return ;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Add_Key
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
inline int
|
||||
VehicleCurveClass::Add_Key (const Vector3 & point,float t)
|
||||
{
|
||||
m_IsDirty = true;
|
||||
return Curve3DClass::Add_Key (point, t);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Remove_Key
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
inline void
|
||||
VehicleCurveClass::Remove_Key (int i)
|
||||
{
|
||||
m_IsDirty = true;
|
||||
Curve3DClass::Remove_Key (i);
|
||||
return ;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Clear_Keys
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
inline void
|
||||
VehicleCurveClass::Clear_Keys (void)
|
||||
{
|
||||
m_IsDirty = true;
|
||||
Curve3DClass::Clear_Keys ();
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
#endif //__VEHICLE_CURVE_H
|
||||
|
||||
539
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vp.cpp
Normal file
539
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vp.cpp
Normal file
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/vp.cpp $*
|
||||
* *
|
||||
* Org Author:: Hector Yee *
|
||||
* *
|
||||
* Author : Kenny Mitchell *
|
||||
* *
|
||||
* $Modtime:: 06/26/02 4:04p $*
|
||||
* *
|
||||
* $Revision:: 12 $*
|
||||
* *
|
||||
* 06/26/02 KM Matrix name change to avoid MAX conflicts *
|
||||
*---------------------------------------------------------------------------------------------*/
|
||||
|
||||
#include "vp.h"
|
||||
#include "vector2.h"
|
||||
#include "vector3.h"
|
||||
#include "vector4.h"
|
||||
#include "matrix3d.h"
|
||||
#include "matrix4.h"
|
||||
#include "wwdebug.h"
|
||||
#include "cpudetect.h"
|
||||
#include <memory.h>
|
||||
|
||||
#define SHUFFLE(x, y, z, w) (((x)&3)<< 6|((y)&3)<<4|((z)&3)<< 2|((w)&3))
|
||||
#define BROADCAST(XMM, INDEX) __asm shufps XMM,XMM,(((INDEX)&3)<< 6|((INDEX)&3)<<4|((INDEX)&3)<< 2|((INDEX)&3))
|
||||
|
||||
#define TRANSPOSE(BX, BY, BZ, BW, TV) \
|
||||
__asm movaps TV,BZ \
|
||||
__asm unpcklps BZ,BW \
|
||||
__asm unpckhps TV,BW \
|
||||
__asm movaps BW,BX \
|
||||
__asm unpcklps BX,BY \
|
||||
__asm unpckhps BW,BY \
|
||||
__asm movaps BY,BX \
|
||||
__asm shufps BX,BZ,SHUFFLE(1, 0, 1, 0) \
|
||||
__asm shufps BY,BZ,SHUFFLE(3, 2, 3, 2) \
|
||||
__asm movaps BZ,BW \
|
||||
__asm shufps BZ,TV,SHUFFLE(1, 0, 1, 0) \
|
||||
__asm shufps BW,TV,SHUFFLE(3, 2, 3, 2)
|
||||
|
||||
|
||||
void VectorProcessorClass::Prefetch(void* address)
|
||||
{
|
||||
#if defined (__ICL) // Detect Intel compiler
|
||||
if (CPUDetectClass::_Has_SSE_Instruction_Set()) {
|
||||
__asm {
|
||||
// mov edx,address
|
||||
// mov eax,[edx]
|
||||
// prefetchT1 address
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static Vector4 lastrow(0.0f,0.0f,0.0f,1.0f);
|
||||
void VectorProcessorClass::Transform (Vector3* dst,const Vector3 *src, const Matrix3D& mtx, const int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
|
||||
#if defined (__ICL) // Detect Intel compiler
|
||||
if (CPUDetectClass::_Has_SSE_Instruction_Set()) {
|
||||
|
||||
__asm {
|
||||
mov edx,dst
|
||||
mov eax,src
|
||||
mov ebx,mtx
|
||||
mov edi,count
|
||||
|
||||
movups xmm4,[ebx+0]
|
||||
movups xmm5,[ebx+16]
|
||||
movups xmm6,[ebx+32]
|
||||
movups xmm7,lastrow //[ebx+48]
|
||||
|
||||
TRANSPOSE(xmm4, xmm5, xmm6, xmm7, xmm0);
|
||||
|
||||
shufps xmm4,xmm4,SHUFFLE(2,1,0,0)
|
||||
shufps xmm5,xmm5,SHUFFLE(2,1,0,0)
|
||||
shufps xmm6,xmm6,SHUFFLE(2,1,0,0)
|
||||
shufps xmm7,xmm7,SHUFFLE(2,1,0,0)
|
||||
|
||||
mov esi,edx
|
||||
_lp:
|
||||
test edi,edi
|
||||
jz _ulos
|
||||
test esi,0xf
|
||||
jz _aligned
|
||||
movss xmm0,[eax]
|
||||
movss xmm1,[eax+4]
|
||||
movss xmm2,[eax+8]
|
||||
BROADCAST(xmm0,0)
|
||||
BROADCAST(xmm1,0)
|
||||
BROADCAST(xmm2,0)
|
||||
mulps xmm0,xmm4
|
||||
mulps xmm1,xmm5
|
||||
mulps xmm2,xmm6
|
||||
addps xmm0,xmm1
|
||||
addps xmm0,xmm2
|
||||
addps xmm0,xmm7
|
||||
movss [edx],xmm0
|
||||
movhps [edx+4],xmm0
|
||||
add eax,12
|
||||
add edx,12
|
||||
add esi,12
|
||||
dec edi
|
||||
jmp _lp
|
||||
_aligned:
|
||||
|
||||
mov esi,1
|
||||
|
||||
mov ecx,edi
|
||||
and edi,3
|
||||
and ecx,~3
|
||||
jz _lp
|
||||
|
||||
lea ecx,[ecx+ecx*2]
|
||||
shl ecx,2
|
||||
add eax,ecx
|
||||
add edx,ecx
|
||||
neg ecx
|
||||
|
||||
cmp dword ptr [ebx+12],0
|
||||
jne _xlatelp
|
||||
cmp dword ptr [ebx+28],0
|
||||
jne _xlatelp
|
||||
cmp dword ptr [ebx+44],0
|
||||
jne _xlatelp
|
||||
jmp _noxlatelp
|
||||
|
||||
align 16
|
||||
|
||||
_noxlatelp:
|
||||
prefetchnta [eax+ecx+48]
|
||||
prefetchnta [eax+ecx+48+32]
|
||||
|
||||
movss xmm0,[eax+ecx]
|
||||
BROADCAST(xmm0,0)
|
||||
movss xmm1,[eax+ecx+4]
|
||||
BROADCAST(xmm1,0)
|
||||
movss xmm2,[eax+ecx+8]
|
||||
BROADCAST(xmm2,0)
|
||||
mulps xmm0,xmm4
|
||||
mulps xmm1,xmm5
|
||||
mulps xmm2,xmm6
|
||||
addps xmm0,xmm1
|
||||
addps xmm0,xmm2
|
||||
|
||||
movss xmm1,[eax+ecx+12]
|
||||
BROADCAST(xmm1,0)
|
||||
movss xmm2,[eax+ecx+16]
|
||||
BROADCAST(xmm2,0)
|
||||
movss xmm3,[eax+ecx+20]
|
||||
BROADCAST(xmm3,0)
|
||||
mulps xmm1,xmm4
|
||||
mulps xmm2,xmm5
|
||||
mulps xmm3,xmm6
|
||||
addps xmm1,xmm2
|
||||
addps xmm3,xmm1
|
||||
|
||||
movss xmm0,xmm3
|
||||
shufps xmm0,xmm0,SHUFFLE(0,3,2,1)
|
||||
|
||||
movaps [edx+ecx],xmm0
|
||||
|
||||
prefetcht0 [edx+ecx+48]
|
||||
prefetcht0 [edx+ecx+48+32]
|
||||
|
||||
movss xmm0,[eax+ecx+24]
|
||||
BROADCAST(xmm0,0)
|
||||
movss xmm1,[eax+ecx+24+4]
|
||||
BROADCAST(xmm1,0)
|
||||
movss xmm2,[eax+ecx+24+8]
|
||||
BROADCAST(xmm2,0)
|
||||
mulps xmm0,xmm4
|
||||
mulps xmm1,xmm5
|
||||
mulps xmm2,xmm6
|
||||
addps xmm0,xmm1
|
||||
addps xmm0,xmm2
|
||||
|
||||
shufps xmm3,xmm0,SHUFFLE(2,1,3,2)
|
||||
movaps [edx+ecx+16],xmm3
|
||||
|
||||
movss xmm1,[eax+ecx+24+12]
|
||||
BROADCAST(xmm1,0)
|
||||
movss xmm2,[eax+ecx+24+16]
|
||||
BROADCAST(xmm2,0)
|
||||
movss xmm3,[eax+ecx+24+20]
|
||||
BROADCAST(xmm3,0)
|
||||
mulps xmm1,xmm4
|
||||
mulps xmm2,xmm5
|
||||
mulps xmm3,xmm6
|
||||
addps xmm1,xmm2
|
||||
addps xmm1,xmm3
|
||||
|
||||
shufps xmm0,xmm0,SHUFFLE(2,1,0,3)
|
||||
movss xmm1,xmm0
|
||||
movaps [edx+ecx+32],xmm1
|
||||
|
||||
add ecx,48
|
||||
js _noxlatelp
|
||||
|
||||
jmp _lp
|
||||
|
||||
align 16
|
||||
|
||||
_xlatelp:
|
||||
prefetchnta [eax+ecx+48]
|
||||
prefetchnta [eax+ecx+48+32]
|
||||
|
||||
movss xmm0,[eax+ecx]
|
||||
BROADCAST(xmm0,0)
|
||||
movss xmm1,[eax+ecx+4]
|
||||
BROADCAST(xmm1,0)
|
||||
movss xmm2,[eax+ecx+8]
|
||||
BROADCAST(xmm2,0)
|
||||
mulps xmm0,xmm4
|
||||
mulps xmm1,xmm5
|
||||
mulps xmm2,xmm6
|
||||
addps xmm0,xmm1
|
||||
addps xmm0,xmm2
|
||||
addps xmm0,xmm7
|
||||
|
||||
movss xmm1,[eax+ecx+12]
|
||||
BROADCAST(xmm1,0)
|
||||
movss xmm2,[eax+ecx+16]
|
||||
BROADCAST(xmm2,0)
|
||||
movss xmm3,[eax+ecx+20]
|
||||
BROADCAST(xmm3,0)
|
||||
mulps xmm1,xmm4
|
||||
mulps xmm2,xmm5
|
||||
mulps xmm3,xmm6
|
||||
addps xmm1,xmm2
|
||||
addps xmm3,xmm1
|
||||
addps xmm3,xmm7
|
||||
|
||||
movss xmm0,xmm3
|
||||
shufps xmm0,xmm0,SHUFFLE(0,3,2,1)
|
||||
movaps [edx+ecx],xmm0
|
||||
|
||||
prefetcht0 [edx+ecx+48]
|
||||
prefetcht0 [edx+ecx+48+32]
|
||||
|
||||
movss xmm0,[eax+ecx+24]
|
||||
BROADCAST(xmm0,0)
|
||||
movss xmm1,[eax+ecx+24+4]
|
||||
BROADCAST(xmm1,0)
|
||||
movss xmm2,[eax+ecx+24+8]
|
||||
BROADCAST(xmm2,0)
|
||||
mulps xmm0,xmm4
|
||||
mulps xmm1,xmm5
|
||||
mulps xmm2,xmm6
|
||||
addps xmm0,xmm1
|
||||
addps xmm0,xmm2
|
||||
addps xmm0,xmm7
|
||||
|
||||
shufps xmm3,xmm0,SHUFFLE(2,1,3,2)
|
||||
movaps [edx+ecx+16],xmm3
|
||||
|
||||
movss xmm1,[eax+ecx+24+12]
|
||||
BROADCAST(xmm1,0)
|
||||
movss xmm2,[eax+ecx+24+16]
|
||||
BROADCAST(xmm2,0)
|
||||
movss xmm3,[eax+ecx+24+20]
|
||||
BROADCAST(xmm3,0)
|
||||
mulps xmm1,xmm4
|
||||
mulps xmm2,xmm5
|
||||
mulps xmm3,xmm6
|
||||
addps xmm1,xmm2
|
||||
addps xmm1,xmm3
|
||||
addps xmm1,xmm7
|
||||
|
||||
shufps xmm0,xmm0,SHUFFLE(2,1,0,3)
|
||||
movss xmm1,xmm0
|
||||
|
||||
movaps [edx+ecx+32],xmm1
|
||||
|
||||
add ecx,48
|
||||
js _xlatelp
|
||||
|
||||
jmp _lp
|
||||
_ulos:
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
mtx.mulVector3Array(src, dst, count);
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Transform(Vector4* dst,const Vector3 *src, const Matrix4x4& matrix, const int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i]=matrix*src[i];
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Copy(Vector2 *dst, const Vector2 *src, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
memcpy(dst,src,sizeof(Vector2)*count);
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Copy(unsigned *dst, const unsigned *src, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
memcpy(dst,src,sizeof(unsigned)*count);
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Copy(Vector3 *dst, const Vector3 *src, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
memcpy(dst,src,sizeof(Vector3)*count);
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Copy(Vector4 *dst, const Vector4 *src, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
memcpy(dst,src,sizeof(Vector4)*count);
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Copy(Vector4 *dst,const Vector3 *src, const float * srca, const int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i].X=src[i].X;
|
||||
dst[i].Y=src[i].Y;
|
||||
dst[i].Z=src[i].Z;
|
||||
dst[i].W=srca[i];
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Copy(Vector4 *dst,const Vector3 *src, const float srca, const int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i].X=src[i].X;
|
||||
dst[i].Y=src[i].Y;
|
||||
dst[i].Z=src[i].Z;
|
||||
dst[i].W=srca;
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Copy(Vector4 *dst,const Vector3 &src, const float * srca, const int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i].X=src.X;
|
||||
dst[i].Y=src.Y;
|
||||
dst[i].Z=src.Z;
|
||||
dst[i].W=srca[i];
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::CopyIndexed (unsigned *dst,const unsigned *src, const unsigned int *index, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i]=src[index[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::CopyIndexed (Vector2 *dst,const Vector2 *src, const unsigned int *index, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i]=src[index[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::CopyIndexed (Vector3 *dst,const Vector3 *src, const unsigned int *index, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i]=src[index[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::CopyIndexed (Vector4 *dst,const Vector4 *src, const unsigned int *index, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i]=src[index[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::CopyIndexed(unsigned char* dst, const unsigned char* src, const unsigned int *index, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i]=src[index[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::CopyIndexed(float* dst, float* src, const unsigned int *index, int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i]=src[index[i]];
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Clamp(Vector4 *dst,const Vector4 *src, const float min, const float max, const int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
{
|
||||
dst[i].X=(src[i].X<min)?min:src[i].X;
|
||||
dst[i].X=(src[i].X>max)?max:src[i].X;
|
||||
|
||||
dst[i].Y=(src[i].Y<min)?min:src[i].Y;
|
||||
dst[i].Y=(src[i].Y>max)?max:src[i].Y;
|
||||
|
||||
dst[i].Z=(src[i].Z<min)?min:src[i].Z;
|
||||
dst[i].Z=(src[i].Z>max)?max:src[i].Z;
|
||||
|
||||
dst[i].W=(src[i].W<min)?min:src[i].W;
|
||||
dst[i].W=(src[i].W>max)?max:src[i].W;
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Clear(Vector3*dst, const int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
memset(dst,0,sizeof(Vector3)*count);
|
||||
}
|
||||
|
||||
|
||||
void VectorProcessorClass::Normalize(Vector3 *dst, const int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
int i;
|
||||
|
||||
for (i=0; i<count; i++)
|
||||
dst[i].Normalize();
|
||||
}
|
||||
|
||||
void VectorProcessorClass::MinMax(Vector3 *src, Vector3 &min, Vector3 &max, const int count)
|
||||
{
|
||||
if (count<=0) return;
|
||||
min=*src;
|
||||
max=*src;
|
||||
|
||||
int i;
|
||||
|
||||
for (i=1; i<count; i++)
|
||||
{
|
||||
min.X=MIN(min.X,src[i].X);
|
||||
min.Y=MIN(min.Y,src[i].Y);
|
||||
min.Z=MIN(min.Z,src[i].Z);
|
||||
|
||||
max.X=MAX(max.X,src[i].X);
|
||||
max.Y=MAX(max.Y,src[i].Y);
|
||||
max.Z=MAX(max.Z,src[i].Z);
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::MulAdd(float * dest,float multiplier,float add,int count)
|
||||
{
|
||||
for (int i=0; i<count; i++) {
|
||||
dest[i] = dest[i] * multiplier + add;
|
||||
}
|
||||
}
|
||||
|
||||
void VectorProcessorClass::DotProduct(float *dst, const Vector3 &a, const Vector3 *b,const int count)
|
||||
{
|
||||
for (int i=0; i<count; i++)
|
||||
dst[i]=Vector3::Dot_Product(a,b[i]);
|
||||
}
|
||||
|
||||
void VectorProcessorClass::ClampMin(float *dst, float *src, const float min, const int count)
|
||||
{
|
||||
for (int i=0; i<count; i++)
|
||||
dst[i]=(src[i]>min?src[i]:min);
|
||||
}
|
||||
|
||||
void VectorProcessorClass::Power(float *dst, float *src, const float pow, const int count)
|
||||
{
|
||||
for (int i=0; i<count; i++)
|
||||
dst[i]=powf(src[i],pow);
|
||||
}
|
||||
93
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vp.h
Normal file
93
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/vp.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/vp.h $*
|
||||
* *
|
||||
* Org Author:: Hector Yee *
|
||||
* *
|
||||
* Author : Kenny Mitchell *
|
||||
* *
|
||||
* $Modtime:: 06/26/02 4:04p $*
|
||||
* *
|
||||
* $Revision:: 13 $*
|
||||
* *
|
||||
* 06/26/02 KM Matrix name change to avoid MAX conflicts *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* Transform - transforms a vector array given Matrix3D *
|
||||
* Copy - Copies data from source to destination *
|
||||
* CopyIndexed-copies dst[]=src[index[]] *
|
||||
* Clear - clears array to zero *
|
||||
* Normalize - normalize the array *
|
||||
* MinMax - Finds the min and max of the array *
|
||||
* *
|
||||
*----------------------------------------------------------------------------------------------*
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef VECTORPROCESSOR_H
|
||||
#define VECTORPROCESSOR_H
|
||||
|
||||
class Vector2;
|
||||
class Vector3;
|
||||
class Vector4;
|
||||
class Matrix3D;
|
||||
class Matrix4x4;
|
||||
|
||||
class VectorProcessorClass
|
||||
{
|
||||
public:
|
||||
static void Transform(Vector3* dst,const Vector3 *src, const Matrix3D& matrix, const int count);
|
||||
static void Transform(Vector4* dst,const Vector3 *src, const Matrix4x4& matrix, const int count);
|
||||
static void Copy(unsigned *dst,const unsigned *src, const int count);
|
||||
static void Copy(Vector2 *dst,const Vector2 *src, const int count);
|
||||
static void Copy(Vector3 *dst,const Vector3 *src, const int count);
|
||||
static void Copy(Vector4 *dst,const Vector4 *src, const int count);
|
||||
static void Copy(Vector4 *dst,const Vector3 *src, const float * srca, const int count);
|
||||
static void Copy(Vector4 *dst,const Vector3 *src, const float srca, const int count);
|
||||
static void Copy(Vector4 *dst,const Vector3 &src, const float * srca, const int count);
|
||||
static void CopyIndexed(unsigned *dst,const unsigned *src, const unsigned int *index, const int count);
|
||||
static void CopyIndexed(Vector2 *dst,const Vector2 *src, const unsigned int *index, const int count);
|
||||
static void CopyIndexed(Vector3 *dst,const Vector3 *src, const unsigned int *index, const int count);
|
||||
static void CopyIndexed(Vector4 *dst,const Vector4 *src, const unsigned int *index, const int count);
|
||||
static void CopyIndexed(unsigned char* dst, const unsigned char* src, const unsigned int *index, int count);
|
||||
static void CopyIndexed(float* dst, float* src, const unsigned int *index, int count);
|
||||
static void Clamp(Vector4 *dst,const Vector4 *src, const float min, const float max, const int count);
|
||||
static void Clear (Vector3 *dst, const int count);
|
||||
static void Normalize(Vector3 *dst, const int count);
|
||||
static void MinMax(Vector3 *src, Vector3 &min, Vector3 &max, const int count);
|
||||
|
||||
static void MulAdd(float * dest,float multiplier,float add,int count);
|
||||
|
||||
static void Prefetch(void* address);
|
||||
|
||||
static void DotProduct(float *dst, const Vector3 &a, const Vector3 *b,const int count);
|
||||
static void ClampMin(float *dst, float *src, const float min, const int count);
|
||||
static void Power(float *dst, float *src, const float pow, const int count);
|
||||
};
|
||||
|
||||
#endif // VECTORPROCESSOR_H
|
||||
95
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/wwmath.cpp
Normal file
95
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/wwmath.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/wwmath.cpp $*
|
||||
* *
|
||||
* Author:: Eric_c *
|
||||
* *
|
||||
* $Modtime:: 5/10/01 10:52p $*
|
||||
* *
|
||||
* $Revision:: 11 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#include "wwmath.h"
|
||||
#include "wwhack.h"
|
||||
#include "lookuptable.h"
|
||||
#include <stdlib.h>
|
||||
#include "wwdebug.h"
|
||||
#include "wwprofile.h"
|
||||
|
||||
// TODO: convert to use loouptablemanager...
|
||||
float _FastAcosTable[ARC_TABLE_SIZE];
|
||||
float _FastAsinTable[ARC_TABLE_SIZE];
|
||||
float _FastSinTable[SIN_TABLE_SIZE];
|
||||
float _FastInvSinTable[SIN_TABLE_SIZE];
|
||||
|
||||
void WWMath::Init(void)
|
||||
{
|
||||
LookupTableMgrClass::Init();
|
||||
|
||||
for (int a=0;a<ARC_TABLE_SIZE;++a) {
|
||||
float cv=float(a-ARC_TABLE_SIZE/2)*(1.0f/(ARC_TABLE_SIZE/2));
|
||||
_FastAcosTable[a]=acos(cv);
|
||||
_FastAsinTable[a]=asin(cv);
|
||||
}
|
||||
|
||||
for (a=0;a<SIN_TABLE_SIZE;++a) {
|
||||
float cv= (float)a * 2.0f * WWMATH_PI / SIN_TABLE_SIZE; //float(a-SIN_TABLE_SIZE/2)*(1.0f/(SIN_TABLE_SIZE/2));
|
||||
_FastSinTable[a]=sin(cv);
|
||||
|
||||
if (a>0) {
|
||||
_FastInvSinTable[a]=1.0f/_FastSinTable[a];
|
||||
} else {
|
||||
_FastInvSinTable[a]=WWMATH_FLOAT_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WWMath::Shutdown(void)
|
||||
{
|
||||
LookupTableMgrClass::Shutdown();
|
||||
}
|
||||
|
||||
float WWMath::Random_Float(void)
|
||||
{
|
||||
return ((float)(rand() & 0xFFF)) / (float)(0xFFF);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Force link some modules from this library.
|
||||
*/
|
||||
void Do_Force_Links(void)
|
||||
{
|
||||
FORCE_LINK(curve);
|
||||
FORCE_LINK(hermitespline);
|
||||
FORCE_LINK(catmullromspline);
|
||||
FORCE_LINK(cardinalspline);
|
||||
FORCE_LINK(tcbspline);
|
||||
}
|
||||
|
||||
484
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/wwmath.dsp
Normal file
484
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/wwmath.dsp
Normal file
@@ -0,0 +1,484 @@
|
||||
# Microsoft Developer Studio Project File - Name="wwmath" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=wwmath - Win32 DebugW3D
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "wwmath.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "wwmath.mak" CFG="wwmath - Win32 DebugW3D"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "wwmath - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "wwmath - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "wwmath - Win32 Profile" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "wwmath - Win32 Internal" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "wwmath - Win32 DebugW3D" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""$/Commando/Code/wwmath", UEFAAAAA"
|
||||
# PROP Scc_LocalPath "."
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "wwmath - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "wwmath_3"
|
||||
# PROP BASE Intermediate_Dir "wwmath_3"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /I "..\Library" /D "G_CODE_BASE" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /c
|
||||
# ADD CPP /nologo /G6 /MDd /W3 /WX /Gi /GX /Zi /O2 /Ob2 /I "..\wwlib" /I "..\wwdebug" /I "..\wwsaveload" /D "G_CODE_BASE" /D "DIRECTX" /D "_DEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /YX /FD /c
|
||||
# SUBTRACT CPP /Fr
|
||||
# ADD BASE RSC /l 0x409
|
||||
# ADD RSC /l 0x409
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo /out:"..\Libs\wwmathd.lib"
|
||||
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWMathDebug.lib"
|
||||
|
||||
!ELSEIF "$(CFG)" == "wwmath - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "wwmath_4"
|
||||
# PROP BASE Intermediate_Dir "wwmath_4"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /I "..\Library" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
|
||||
# ADD CPP /nologo /G6 /MD /W3 /WX /Gi /GX /O2 /Ob2 /I "..\wwlib" /I "..\wwdebug" /I "..\wwsaveload" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "NDEBUG" /D "WIN32" /D "IG_DEBUG_STACKTRACE" /YX /FD /c
|
||||
# SUBTRACT CPP /Fr
|
||||
# ADD BASE RSC /l 0x409
|
||||
# ADD RSC /l 0x409
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo /out:"..\Libs\wwmath.lib"
|
||||
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWMath.lib"
|
||||
|
||||
!ELSEIF "$(CFG)" == "wwmath - Win32 Profile"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "wwmath__"
|
||||
# PROP BASE Intermediate_Dir "wwmath__"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Profile"
|
||||
# PROP Intermediate_Dir "Profile"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /I "..\Library" /I "..\wwdebug" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /FR /YX /FD /c
|
||||
# ADD CPP /nologo /MD /W3 /WX /GX /Zi /O2 /Op /Ob2 /I "..\wwlib" /I "..\wwdebug" /I "..\wwsaveload" /D "NDEBUG" /D "WWDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /D "_PROFILE" /YX /FD /Gh /c
|
||||
# ADD BASE RSC /l 0x409
|
||||
# ADD RSC /l 0x409
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo /out:"..\Libs\release\wwmath.lib"
|
||||
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWMathProfile.lib"
|
||||
|
||||
!ELSEIF "$(CFG)" == "wwmath - Win32 Internal"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Internal"
|
||||
# PROP BASE Intermediate_Dir "Internal"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Internal"
|
||||
# PROP Intermediate_Dir "Internal"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MD /W4 /WX /Gi /GX /O2 /Ob2 /I "..\wwlib" /I "..\wwdebug" /I "..\wwsaveload" /D "NDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /YX /FD /c
|
||||
# SUBTRACT BASE CPP /Fr
|
||||
# ADD CPP /nologo /G6 /MD /W3 /WX /Gi /GX /Zi /O2 /I "..\wwlib" /I "..\wwdebug" /I "..\wwsaveload" /D "NDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /D "_INTERNAL" /YX /FD /c
|
||||
# SUBTRACT CPP /Fr
|
||||
# ADD BASE RSC /l 0x409
|
||||
# ADD RSC /l 0x409
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo /out:"..\..\..\Lib\WWMath.lib"
|
||||
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWMathInternal.lib"
|
||||
|
||||
!ELSEIF "$(CFG)" == "wwmath - Win32 DebugW3D"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "DebugW3D"
|
||||
# PROP BASE Intermediate_Dir "DebugW3D"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "DebugW3D"
|
||||
# PROP Intermediate_Dir "DebugW3D"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MDd /W3 /WX /Gm /Gi /GR /GX /ZI /Od /I "..\wwlib" /I "..\wwdebug" /I "..\wwsaveload" /D "G_CODE_BASE" /D "DIRECTX" /D "_DEBUG" /D "WWDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /Fr /YX /FD /c
|
||||
# ADD CPP /nologo /G6 /MDd /W3 /WX /Gm /Gi /GX /ZI /Od /I "..\wwlib" /I "..\wwdebug" /I "..\wwsaveload" /D "G_CODE_BASE" /D "DIRECTX" /D "_DEBUG" /D "WWDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /YX /FD /c
|
||||
# SUBTRACT CPP /Fr
|
||||
# ADD BASE RSC /l 0x409
|
||||
# ADD RSC /l 0x409
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo /out:"..\..\..\Lib\WWMathDebug.lib"
|
||||
# ADD LIB32 /nologo /out:"..\..\..\Lib\WWMathDebugW3D.lib"
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "wwmath - Win32 Debug"
|
||||
# Name "wwmath - Win32 Release"
|
||||
# Name "wwmath - Win32 Profile"
|
||||
# Name "wwmath - Win32 Internal"
|
||||
# Name "wwmath - Win32 DebugW3D"
|
||||
# Begin Group "Source"
|
||||
|
||||
# PROP Default_Filter "c;cpp"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\aabox.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\aabtreecull.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\cardinalspline.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\catmullromspline.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmath.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathaabox.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathaabtri.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathfrustum.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathline.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathobbobb.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathobbox.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathobbtri.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathplane.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathsphere.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\cullsys.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\curve.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\euler.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\frustum.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\gridcull.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hermitespline.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lineseg.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lookuptable.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\matrix3.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\matrix3d.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\matrix4.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\obbox.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ode.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pot.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\quat.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tcbspline.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tri.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v3_rnd.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vehiclecurve.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vp.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wwmath.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Headers"
|
||||
|
||||
# PROP Default_Filter "h"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\aabox.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\aabtreecull.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\aaplane.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\cardinalspline.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\castres.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\catmullromspline.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmath.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathaabox.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathfrustum.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathinlines.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathline.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\colmathplane.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\cullsys.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\culltype.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\curve.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\euler.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\frustum.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\gridcull.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hermitespline.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lineseg.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\lookuptable.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\matrix3.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\matrix3d.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\matrix4.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\obbox.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ode.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\plane.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\pot.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\quat.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\rect.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\sphere.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tcbspline.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tri.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\v3_rnd.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vector2.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vector2i.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vector3.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Vector3i.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vector4.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vehiclecurve.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\vp.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wwmath.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\wwmathids.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
||||
658
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/wwmath.h
Normal file
658
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/wwmath.h
Normal file
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/wwmath.h $*
|
||||
* *
|
||||
* Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Modtime:: 8/26/01 2:22p $*
|
||||
* *
|
||||
* $Revision:: 64 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef WWMATH_H
|
||||
#define WWMATH_H
|
||||
|
||||
#include "always.h"
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
|
||||
/*
|
||||
** Some global constants.
|
||||
*/
|
||||
#define WWMATH_EPSILON 0.0001f
|
||||
#define WWMATH_EPSILON2 WWMATH_EPSILON * WWMATH_EPSILON
|
||||
#define WWMATH_PI 3.141592654f
|
||||
#define WWMATH_FLOAT_MAX (FLT_MAX)
|
||||
#define WWMATH_FLOAT_MIN (FLT_MIN)
|
||||
#define WWMATH_SQRT2 1.414213562f
|
||||
#define WWMATH_SQRT3 1.732050808f
|
||||
#define WWMATH_OOSQRT2 0.707106781f
|
||||
#define WWMATH_OOSQRT3 0.577350269f
|
||||
|
||||
// (DRM 05/07/01) Temporarily eliminated _fastcall
|
||||
// on non-Microsoft compatible compilers. Jani
|
||||
// should be replacing this soon.
|
||||
#ifndef _MSC_VER
|
||||
#define __fastcall
|
||||
#endif // _MSC_VER
|
||||
|
||||
/*
|
||||
** Macros to convert between degrees and radians
|
||||
*/
|
||||
#ifndef RAD_TO_DEG
|
||||
#define RAD_TO_DEG(x) (((double)x)*180.0/WWMATH_PI)
|
||||
#endif
|
||||
|
||||
#ifndef DEG_TO_RAD
|
||||
#define DEG_TO_RAD(x) (((double)x)*WWMATH_PI/180.0)
|
||||
#endif
|
||||
|
||||
#ifndef RAD_TO_DEGF
|
||||
#define RAD_TO_DEGF(x) (((float)x)*180.0f/WWMATH_PI)
|
||||
#endif
|
||||
|
||||
#ifndef DEG_TO_RADF
|
||||
#define DEG_TO_RADF(x) (((float)x)*WWMATH_PI/180.0f)
|
||||
#endif
|
||||
|
||||
|
||||
const int ARC_TABLE_SIZE=1024;
|
||||
const int SIN_TABLE_SIZE=1024;
|
||||
extern float _FastAcosTable[ARC_TABLE_SIZE];
|
||||
extern float _FastAsinTable[ARC_TABLE_SIZE];
|
||||
extern float _FastSinTable[SIN_TABLE_SIZE];
|
||||
extern float _FastInvSinTable[SIN_TABLE_SIZE];
|
||||
|
||||
/*
|
||||
** Some simple math functions which work on the built-in types.
|
||||
** Include the various other header files in the WWMATH library
|
||||
** in order to get matrices, quaternions, etc.
|
||||
*/
|
||||
class WWMath
|
||||
{
|
||||
public:
|
||||
|
||||
// Initialization and Shutdown. Other math sub-systems which require initialization and
|
||||
// shutdown processing will be handled in these functions
|
||||
static void Init(void);
|
||||
static void Shutdown(void);
|
||||
|
||||
// These are meant to be a collection of small math utility functions to be optimized at some point.
|
||||
static WWINLINE float Fabs(float val)
|
||||
{
|
||||
int value=*(int*)&val;
|
||||
value&=0x7fffffff;
|
||||
return *(float*)&value;
|
||||
}
|
||||
|
||||
static WWINLINE int Float_To_Int_Chop(const float& f);
|
||||
static WWINLINE int Float_To_Int_Floor(const float& f);
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
static WWINLINE float Cos(float val);
|
||||
static WWINLINE float Sin(float val);
|
||||
static WWINLINE float Sqrt(float val);
|
||||
static float __fastcall Inv_Sqrt(float a); // Some 30% faster inverse square root than regular C++ compiled, from Intel's math library
|
||||
static WWINLINE long Float_To_Long(float f);
|
||||
#else
|
||||
static float Cos(float val);
|
||||
static float Sin(float val);
|
||||
static float Sqrt(float val);
|
||||
static float Inv_Sqrt(float a);
|
||||
static long Float_To_Long(float f);
|
||||
#endif
|
||||
|
||||
|
||||
static WWINLINE float Fast_Sin(float val);
|
||||
static WWINLINE float Fast_Inv_Sin(float val);
|
||||
static WWINLINE float Fast_Cos(float val);
|
||||
static WWINLINE float Fast_Inv_Cos(float val);
|
||||
|
||||
static WWINLINE float Fast_Acos(float val);
|
||||
static WWINLINE float Acos(float val);
|
||||
static WWINLINE float Fast_Asin(float val);
|
||||
static WWINLINE float Asin(float val);
|
||||
|
||||
|
||||
static float Atan(float x) { return static_cast<float>(atan(x)); }
|
||||
static float Atan2(float y,float x) { return static_cast<float>(atan2(y,x)); }
|
||||
static float Sign(float val);
|
||||
static float Ceil(float val) { return ceilf(val); }
|
||||
static float Floor(float val) { return floorf(val); }
|
||||
static bool Fast_Is_Float_Positive(const float & val);
|
||||
static bool Is_Power_Of_2(const unsigned int val);
|
||||
|
||||
static float Random_Float(void);
|
||||
static float Random_Float(float min,float max);
|
||||
static float Clamp(float val, float min = 0.0f, float max = 1.0f);
|
||||
static double Clamp(double val, double min = 0.0f, double max = 1.0f);
|
||||
static int Clamp_Int(int val, int min_val, int max_val);
|
||||
static float Wrap(float val, float min = 0.0f, float max = 1.0f);
|
||||
static double Wrap(double val, double min = 0.0f, double max = 1.0f);
|
||||
static float Min(float a, float b);
|
||||
static float Max(float a, float b);
|
||||
|
||||
static int Float_As_Int(const float f) { return *((int*)&f); }
|
||||
|
||||
static float Lerp(float a, float b, float lerp );
|
||||
static double Lerp(double a, double b, float lerp );
|
||||
|
||||
static long Float_To_Long(double f);
|
||||
|
||||
static unsigned char Unit_Float_To_Byte(float f) { return (unsigned char)(f*255.0f); }
|
||||
static float Byte_To_Unit_Float(unsigned char byte) { return ((float)byte) / 255.0f; }
|
||||
|
||||
static bool Is_Valid_Float(float x);
|
||||
static bool Is_Valid_Double(double x);
|
||||
|
||||
};
|
||||
|
||||
WWINLINE float WWMath::Sign(float val)
|
||||
{
|
||||
if (val > 0.0f) {
|
||||
return +1.0f;
|
||||
}
|
||||
if (val < 0.0f) {
|
||||
return -1.0f;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
WWINLINE bool WWMath::Fast_Is_Float_Positive(const float & val)
|
||||
{
|
||||
return !((*(int *)(&val)) & 0x80000000);
|
||||
}
|
||||
|
||||
WWINLINE bool WWMath::Is_Power_Of_2(const unsigned int val)
|
||||
{
|
||||
return !((val)&val-1);
|
||||
}
|
||||
|
||||
WWINLINE float WWMath::Random_Float(float min,float max)
|
||||
{
|
||||
return Random_Float() * (max-min) + min;
|
||||
}
|
||||
|
||||
WWINLINE float WWMath::Clamp(float val, float min /*= 0.0f*/, float max /*= 1.0f*/)
|
||||
{
|
||||
if(val < min) return min;
|
||||
if(val > max) return max;
|
||||
return val;
|
||||
}
|
||||
|
||||
WWINLINE double WWMath::Clamp(double val, double min /*= 0.0f*/, double max /*= 1.0f*/)
|
||||
{
|
||||
if(val < min) return min;
|
||||
if(val > max) return max;
|
||||
return val;
|
||||
}
|
||||
|
||||
WWINLINE int WWMath::Clamp_Int(int val, int min_val, int max_val)
|
||||
{
|
||||
if(val < min_val) return min_val;
|
||||
if(val > max_val) return max_val;
|
||||
return val;
|
||||
}
|
||||
|
||||
WWINLINE float WWMath::Wrap(float val, float min /*= 0.0f*/, float max /*= 1.0f*/)
|
||||
{
|
||||
// Implemented as an if rather than a while, to long loops
|
||||
if ( val >= max ) val -= (max-min);
|
||||
if ( val < min ) val += (max-min);
|
||||
|
||||
if ( val < min ) {
|
||||
val = min;
|
||||
}
|
||||
if ( val > max ) {
|
||||
val = max;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
WWINLINE double WWMath::Wrap(double val, double min /*= 0.0f*/, double max /*= 1.0f*/)
|
||||
{
|
||||
// Implemented as an if rather than a while, to long loops
|
||||
if ( val >= max ) val -= (max-min);
|
||||
if ( val < min ) val += (max-min);
|
||||
if ( val < min ) {
|
||||
val = min;
|
||||
}
|
||||
if ( val > max ) {
|
||||
val = max;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
WWINLINE float WWMath::Min(float a, float b)
|
||||
{
|
||||
if (a<b) return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
WWINLINE float WWMath::Max(float a, float b)
|
||||
{
|
||||
if (a>b) return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
WWINLINE float WWMath::Lerp(float a, float b, float lerp )
|
||||
{
|
||||
return (a + (b - a)*lerp);
|
||||
}
|
||||
|
||||
WWINLINE double WWMath::Lerp(double a, double b, float lerp )
|
||||
{
|
||||
return (a + (b - a)*lerp);
|
||||
}
|
||||
|
||||
|
||||
WWINLINE bool WWMath::Is_Valid_Float(float x)
|
||||
{
|
||||
unsigned long * plong = (unsigned long *)(&x);
|
||||
unsigned long exponent = ((*plong) & 0x7F800000) >> (32-9);
|
||||
|
||||
// if exponent is 0xFF, this is a NAN
|
||||
if (exponent == 0xFF) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WWINLINE bool WWMath::Is_Valid_Double(double x)
|
||||
{
|
||||
unsigned long * plong = (unsigned long *)(&x) + 1;
|
||||
unsigned long exponent = ((*plong) & 0x7FF00000) >> (32-12);
|
||||
|
||||
// if exponent is 0x7FF, this is a NAN
|
||||
if (exponent == 0x7FF) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Float to long
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
WWINLINE long WWMath::Float_To_Long(float f)
|
||||
{
|
||||
long i;
|
||||
|
||||
__asm {
|
||||
fld [f]
|
||||
fistp [i]
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
#else
|
||||
WWINLINE long WWMath::Float_To_Long(float f)
|
||||
{
|
||||
return (long) f;
|
||||
}
|
||||
#endif
|
||||
|
||||
WWINLINE long WWMath::Float_To_Long(double f)
|
||||
{
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
long retval;
|
||||
__asm fld qword ptr [f]
|
||||
__asm fistp dword ptr [retval]
|
||||
return retval;
|
||||
#else
|
||||
return (long) f;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Cos
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
WWINLINE float WWMath::Cos(float val)
|
||||
{
|
||||
float retval;
|
||||
__asm {
|
||||
fld [val]
|
||||
fcos
|
||||
fstp [retval]
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#else
|
||||
WWINLINE float WWMath::Cos(float val)
|
||||
{
|
||||
return cosf(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Sin
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
WWINLINE float WWMath::Sin(float val)
|
||||
{
|
||||
float retval;
|
||||
__asm {
|
||||
fld [val]
|
||||
fsin
|
||||
fstp [retval]
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#else
|
||||
WWINLINE float WWMath::Sin(float val)
|
||||
{
|
||||
return sinf(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Fast, table based sin
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE float WWMath::Fast_Sin(float val)
|
||||
{
|
||||
val*=float(SIN_TABLE_SIZE) / (2.0f * WWMATH_PI);
|
||||
|
||||
int idx0=Float_To_Int_Floor(val);
|
||||
int idx1=idx0+1;
|
||||
float frac=val-(float)idx0;
|
||||
|
||||
idx0 = ((unsigned)idx0) & (SIN_TABLE_SIZE-1);
|
||||
idx1 = ((unsigned)idx1) & (SIN_TABLE_SIZE-1);
|
||||
|
||||
return (1.0f - frac) * _FastSinTable[idx0] + frac * _FastSinTable[idx1];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Fast, table based 1.0f/sin
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE float WWMath::Fast_Inv_Sin(float val)
|
||||
{
|
||||
#if 0 // TODO: more testing, not reliable!
|
||||
float index = val * float(SIN_TABLE_SIZE) / (2.0f * WWMATH_PI);
|
||||
|
||||
int idx0=Float_To_Int_Floor(index);
|
||||
int idx1=idx0+1;
|
||||
float frac=val-(float)idx0;
|
||||
|
||||
idx0 = ((unsigned)idx0) & (SIN_TABLE_SIZE-1);
|
||||
idx1 = ((unsigned)idx1) & (SIN_TABLE_SIZE-1);
|
||||
|
||||
// The table becomes inaccurate near 0 and 2pi so fall back to doing a divide.
|
||||
const int BUFFER = 16;
|
||||
if ((idx0 <= BUFFER) || (idx0 >= SIN_TABLE_SIZE-BUFFER-1)) {
|
||||
return 1.0f / WWMath::Fast_Sin(val);
|
||||
} else {
|
||||
return (1.0f - frac) * _FastInvSinTable[idx0] + frac * _FastInvSinTable[idx1];
|
||||
}
|
||||
#else
|
||||
return 1.0f / WWMath::Fast_Sin(val);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Fast, table based cos
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE float WWMath::Fast_Cos(float val)
|
||||
{
|
||||
val+=(WWMATH_PI * 0.5f);
|
||||
val*=float(SIN_TABLE_SIZE) / (2.0f * WWMATH_PI);
|
||||
|
||||
int idx0=Float_To_Int_Floor(val);
|
||||
int idx1=idx0+1;
|
||||
float frac=val-(float)idx0;
|
||||
|
||||
idx0 = ((unsigned)idx0) & (SIN_TABLE_SIZE-1);
|
||||
idx1 = ((unsigned)idx1) & (SIN_TABLE_SIZE-1);
|
||||
|
||||
return (1.0f - frac) * _FastSinTable[idx0] + frac * _FastSinTable[idx1];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Fast, table based 1.0f/cos
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE float WWMath::Fast_Inv_Cos(float val)
|
||||
{
|
||||
#if 0 // TODO: more testing, not reliable!
|
||||
float index = val + (WWMATH_PI * 0.5f);
|
||||
index *= float(SIN_TABLE_SIZE) / (2.0f * WWMATH_PI);
|
||||
|
||||
int idx0=Float_To_Int_Chop(index);
|
||||
int idx1=idx0+1;
|
||||
float frac=val-(float)idx0;
|
||||
|
||||
idx0 = ((unsigned)idx0) & (SIN_TABLE_SIZE-1);
|
||||
idx1 = ((unsigned)idx1) & (SIN_TABLE_SIZE-1);
|
||||
|
||||
// The table becomes inaccurate near 0 and 2pi so fall back to doing a divide.
|
||||
if ((idx0 <= 2) || (idx0 >= SIN_TABLE_SIZE-3)) {
|
||||
return 1.0f / WWMath::Fast_Cos(val);
|
||||
} else {
|
||||
return (1.0f - frac) * _FastInvSinTable[idx0] + frac * _FastInvSinTable[idx1];
|
||||
}
|
||||
#else
|
||||
return 1.0f / WWMath::Fast_Cos(val);
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Fast, table based arc cos
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE float WWMath::Fast_Acos(float val)
|
||||
{
|
||||
// Near -1 and +1, the table becomes too inaccurate
|
||||
if (WWMath::Fabs(val) > 0.975f) {
|
||||
return WWMath::Acos(val);
|
||||
}
|
||||
|
||||
val*=float(ARC_TABLE_SIZE/2);
|
||||
|
||||
int idx0=Float_To_Int_Floor(val);
|
||||
int idx1=idx0+1;
|
||||
float frac=val-(float)idx0;
|
||||
|
||||
idx0+=ARC_TABLE_SIZE/2;
|
||||
idx1+=ARC_TABLE_SIZE/2;
|
||||
|
||||
// we dont even get close to the edge of the table...
|
||||
assert((idx0 >= 0) && (idx0 < ARC_TABLE_SIZE));
|
||||
assert((idx1 >= 0) && (idx1 < ARC_TABLE_SIZE));
|
||||
|
||||
// compute and return the interpolated value
|
||||
return (1.0f - frac) * _FastAcosTable[idx0] + frac * _FastAcosTable[idx1];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Arc cos
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE float WWMath::Acos(float val)
|
||||
{
|
||||
return (float)acos(val);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Fast, table based arc sin
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE float WWMath::Fast_Asin(float val)
|
||||
{
|
||||
// Near -1 and +1, the table becomes too inaccurate
|
||||
if (WWMath::Fabs(val) > 0.975f) {
|
||||
return WWMath::Asin(val);
|
||||
}
|
||||
|
||||
val*=float(ARC_TABLE_SIZE/2);
|
||||
|
||||
int idx0=Float_To_Int_Floor(val);
|
||||
int idx1=idx0+1;
|
||||
float frac=val-(float)idx0;
|
||||
|
||||
idx0+=ARC_TABLE_SIZE/2;
|
||||
idx1+=ARC_TABLE_SIZE/2;
|
||||
|
||||
// we dont even get close to the edge of the table...
|
||||
assert((idx0 >= 0) && (idx0 < ARC_TABLE_SIZE));
|
||||
assert((idx1 >= 0) && (idx1 < ARC_TABLE_SIZE));
|
||||
|
||||
// compute and return the interpolated value
|
||||
return (1.0f - frac) * _FastAsinTable[idx0] + frac * _FastAsinTable[idx1];
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Arc sin
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
WWINLINE float WWMath::Asin(float val)
|
||||
{
|
||||
return (float)asin(val);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Sqrt
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
WWINLINE float WWMath::Sqrt(float val)
|
||||
{
|
||||
float retval;
|
||||
__asm {
|
||||
fld [val]
|
||||
fsqrt
|
||||
fstp [retval]
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#else
|
||||
WWINLINE float WWMath::Sqrt(float val)
|
||||
{
|
||||
return (float)sqrt(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
WWINLINE int WWMath::Float_To_Int_Chop(const float& f)
|
||||
{
|
||||
int a = *reinterpret_cast<const int*>(&f); // take bit pattern of float into a register
|
||||
int sign = (a>>31); // sign = 0xFFFFFFFF if original value is negative, 0 if positive
|
||||
int mantissa = (a&((1<<23)-1))|(1<<23); // extract mantissa and add the hidden bit
|
||||
int exponent = ((a&0x7fffffff)>>23)-127; // extract the exponent
|
||||
int r = ((unsigned int)(mantissa)<<8)>>(31-exponent); // ((1<<exponent)*mantissa)>>24 -- (we know that mantissa > (1<<24))
|
||||
return ((r ^ (sign)) - sign ) &~ (exponent>>31); // add original sign. If exponent was negative, make return value 0.
|
||||
}
|
||||
|
||||
WWINLINE int WWMath::Float_To_Int_Floor (const float& f)
|
||||
{
|
||||
int a = *reinterpret_cast<const int*>(&f); // take bit pattern of float into a register
|
||||
int sign = (a>>31); // sign = 0xFFFFFFFF if original value is negative, 0 if positive
|
||||
a&=0x7fffffff; // we don't need the sign any more
|
||||
|
||||
int exponent = (a>>23)-127; // extract the exponent
|
||||
int expsign = ~(exponent>>31); // 0xFFFFFFFF if exponent is positive, 0 otherwise
|
||||
int imask = ( (1<<(31-(exponent))))-1; // mask for true integer values
|
||||
int mantissa = (a&((1<<23)-1)); // extract mantissa (without the hidden bit)
|
||||
int r = ((unsigned int)(mantissa|(1<<23))<<8)>>(31-exponent); // ((1<<exponent)*(mantissa|hidden bit))>>24 -- (we know that mantissa > (1<<24))
|
||||
|
||||
r = ((r & expsign) ^ (sign)) + ((!((mantissa<<8)&imask)&(expsign^((a-1)>>31)))&sign); // if (fabs(value)<1.0) value = 0; copy sign; if (value < 0 && value==(int)(value)) value++;
|
||||
return r;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Inverse square root
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_IX86)
|
||||
WWINLINE __declspec(naked) float __fastcall WWMath::Inv_Sqrt(float a)
|
||||
{
|
||||
__asm {
|
||||
mov eax, 0be6eb508h
|
||||
mov DWORD PTR [esp-12],03fc00000h ; 1.5 on the stack
|
||||
sub eax, DWORD PTR [esp+4]; a
|
||||
sub DWORD PTR [esp+4], 800000h ; a/2 a=Y0
|
||||
shr eax, 1 ; firs approx in eax=R0
|
||||
mov DWORD PTR [esp-8], eax
|
||||
|
||||
fld DWORD PTR [esp-8] ;r
|
||||
fmul st, st ;r*r
|
||||
fld DWORD PTR [esp-8] ;r
|
||||
fxch st(1)
|
||||
fmul DWORD PTR [esp+4];a ;r*r*y0
|
||||
fld DWORD PTR [esp-12];load 1.5
|
||||
fld st(0)
|
||||
fsub st,st(2) ;r1 = 1.5 - y1
|
||||
;x1 = st(3)
|
||||
;y1 = st(2)
|
||||
;1.5 = st(1)
|
||||
;r1 = st(0)
|
||||
|
||||
fld st(1)
|
||||
fxch st(1)
|
||||
fmul st(3),st ; y2=y1*r1*...
|
||||
fmul st(3),st ; y2=y1*r1*r1
|
||||
fmulp st(4),st ; x2=x1*r1
|
||||
fsub st,st(2) ; r2=1.5-y2
|
||||
;x2=st(3)
|
||||
;y2=st(2)
|
||||
;1.5=st(1)
|
||||
;r2 = st(0)
|
||||
|
||||
fmul st(2),st ;y3=y2*r2*...
|
||||
fmul st(3),st ;x3=x2*r2
|
||||
fmulp st(2),st ;y3=y2*r2*r2
|
||||
fxch st(1)
|
||||
fsubp st(1),st ;r3= 1.5 - y3
|
||||
;x3 = st(1)
|
||||
;r3 = st(0)
|
||||
fmulp st(1), st
|
||||
ret 4
|
||||
}
|
||||
}
|
||||
#else
|
||||
WWINLINE float WWMath::Inv_Sqrt(float val)
|
||||
{
|
||||
return 1.0f / (float)sqrt(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
66
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/wwmathids.h
Normal file
66
GeneralsMD/Code/Libraries/Source/WWVegas/WWMath/wwmathids.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/wwmathids.h $*
|
||||
* *
|
||||
* Original Author:: Greg Hjelstrom *
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 5/04/01 8:42p $*
|
||||
* *
|
||||
* $Revision:: 3 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* Functions: *
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#ifndef WWMATHIDS_H
|
||||
#define WWMATHIDS_H
|
||||
|
||||
#include "saveloadids.h"
|
||||
|
||||
/*
|
||||
** Persist Factory ID's for WWMATH
|
||||
*/
|
||||
enum
|
||||
{
|
||||
WWMATH_CHUNKID_LINEARCURVE1D = CHUNKID_WWMATH_BEGIN,
|
||||
WWMATH_CHUNKID_HERMITESPLINE1D,
|
||||
WWMATH_CHUNKID_CATMULLROMSPLINE1D,
|
||||
WWMATH_CHUNKID_CARDINALSPLINE1D,
|
||||
WWMATH_CHUNKID_TCBSPLINE1D,
|
||||
|
||||
WWMATH_CHUNKID_LINEARCURVE3D = CHUNKID_WWMATH_BEGIN + 0x100,
|
||||
WWMATH_CHUNKID_HERMITESPLINE3D,
|
||||
WWMATH_CHUNKID_CATMULLROMSPLINE3D,
|
||||
WWMATH_CHUNKID_CARDINALSPLINE3D,
|
||||
WWMATH_CHUNKID_TCBSPLINE3D,
|
||||
WWMATH_CHUNKID_VEHICLECURVE
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //WWMATHIDS_H
|
||||
|
||||
Reference in New Issue
Block a user